using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; namespace Infrastructure { /// /// Socket 服务端工具类(你的“接受端”) /// 功能:监听端口,与网关(客户端)建立长连接,支持收发字节数据(byte[]) /// public class SocketGatewayServer : IDisposable { private TcpListener _listener; private bool _isRunning; private Thread _acceptThread; private TcpClient _connectedClient; private NetworkStream _clientStream; private bool _clientConnected; private readonly string _listenIp; private readonly int _listenPort; /// /// 构造函数 /// /// 监听的IP,如 "127.0.0.1" 或 "0.0.0.0" /// 监听的端口,如 8888 public SocketGatewayServer(string listenIp = "127.0.0.1", int listenPort = 8888) { _listenIp = listenIp; _listenPort = listenPort; } /// /// 启动服务端,开始监听网关(客户端)连接 /// public void Start() { if (_isRunning) return; try { IPAddress ipAddress = string.IsNullOrEmpty(_listenIp) || _listenIp == "0.0.0.0" ? IPAddress.Any : IPAddress.Parse(_listenIp); _listener = new TcpListener(ipAddress, _listenPort); _listener.Start(); _isRunning = true; Console.WriteLine($"Socket 服务端已启动,正在监听 [{_listenIp}]:{_listenPort}"); _acceptThread = new Thread(AcceptClient); _acceptThread.IsBackground = true; _acceptThread.Start(); } catch (Exception ex) { Console.WriteLine($"❌ 启动服务端失败: {ex.Message}"); Stop(); } } /// /// 等待并接受一个客户端(网关)连接 /// private void AcceptClient() { try { while (_isRunning) { Console.WriteLine(" 等待网关(客户端)连接..."); TcpClient client = _listener.AcceptTcpClient(); // 阻塞直到客户端连接 Console.WriteLine($"网关(客户端)已连接: {client.Client.RemoteEndPoint}"); StartReceiving(); lock (this) { // 断开之前的连接(如果存在) _connectedClient?.Close(); _connectedClient = client; _clientStream = client.GetStream(); _clientConnected = true; Console.WriteLine("已建立长连接,可以开始收发字节数据"); } } } catch (Exception ex) { if (_isRunning) Console.WriteLine($"接受客户端时出错: {ex.Message}"); } } /// /// 向网关(客户端)发送字节数据(byte[]) /// /// 要发送的字节数据 /// 是否发送成功 public bool SendToGateway(byte[] data) { if (!_clientConnected || _clientStream == null || _connectedClient == null) { Console.WriteLine(" 未连接到网关,无法发送数据"); return false; } try { _clientStream.Write(data, 0, data.Length); Console.WriteLine($" 已发送 {data.Length} 字节数据给网关"); return true; } catch (Exception ex) { Console.WriteLine($"发送数据失败: {ex.Message}"); DisconnectClient(); return false; } } /// /// (可选)接收来自网关的字节数据 /// public void StartReceiving() { Thread receiveThread = new Thread(ReceiveLoop); receiveThread.IsBackground = true; receiveThread.Start(); } private void ReceiveLoop() { byte[] buffer = new byte[4096]; // 可根据需求调整缓冲区大小 try { while (_clientConnected && _connectedClient != null && _clientStream != null) { if (_clientStream.DataAvailable) { int bytesRead = _clientStream.Read(buffer, 0, buffer.Length); if (bytesRead > 0) { byte[] receivedData = new byte[bytesRead]; Buffer.BlockCopy(buffer, 0, receivedData, 0, bytesRead); Console.WriteLine($"收到来自网关的 {bytesRead} 字节数据"); // 🔧 新增:将收到的 byte[] 使用 GBK 编码转换为字符串 // string receivedText = Encoding.GetEncoding("GBK").GetString(receivedData); // Console.WriteLine($"GBK 解码后的报文内容: {receivedText}"); PrintBytesAsHex(receivedData); // TODO: 你可以在这里进一步处理 receivedText 或 receivedData } } else { Thread.Sleep(100); // 避免空转消耗 CPU } } } catch (Exception ex) { Console.WriteLine($"接收数据时出错: {ex.Message}"); } finally { Console.WriteLine("接收线程已退出"); } } /// /// 将字节数组转换为十六进制字符串并打印 /// /// 要转换的字节数组 static void PrintBytesAsHex(byte[] bytes) { if (bytes == null || bytes.Length == 0) { Console.WriteLine("字节数组为空或长度为0。"); return; } // 使用 StringBuilder 或直接拼接,这里使用 String.Join 和格式化 string hexString = BitConverter.ToString(bytes).Replace("-", " "); // 可选:用空格分隔每个字节 // 或者不替换,就是用 "-" 分隔:string hexString = BitConverter.ToString(bytes); Console.WriteLine("字节数据的十六进制表示为:"+ hexString); } private void DisconnectClient() { lock (this) { _clientConnected = false; _clientStream?.Close(); _connectedClient?.Close(); _clientStream = null; _connectedClient = null; Console.WriteLine("🔌 已断开与网关的连接"); } } public void Stop() { _isRunning = false; DisconnectClient(); _listener?.Stop(); Console.WriteLine("🛑 Socket 服务端已停止"); } public void Dispose() { Stop(); GC.SuppressFinalize(this); } /// /// 计算多个 byte[] 数组中所有字节之和,然后对 256 取余,返回校验字节(0~255) /// /// 多个 byte[] 数组,可以是任意数量 /// 校验和,一个字节(0~255),即:所有字节之和 % 256 public static byte CalculateChecksum(params byte[][] byteArrays) { int sum = 0; // 遍历每一个 byte[] 数组 foreach (byte[] bytes in byteArrays) { if (bytes == null) continue; // 如果某个数组为空,跳过(你也可以选择抛异常) // 累加该数组中的每一个字节 foreach (byte b in bytes) { sum += b; // byte 自动提升为 int,安全累加 } } // 计算校验和:总和 % 256,然后转为 byte(范围保证是 0~255) return (byte)(sum % 256); } } }