使用Socket接收病理设备数据遇断开连接、无法自动重收问题咨询
现有代码问题排查
你的代码存在3个核心问题:
- 采用同步阻塞
Receive方式,单线程处理速度上限低,当设备发送速率高于你程序的接收处理速率时,Socket内核缓冲区被占满,后续设备发送的包被丢弃,设备端发送超时就会主动断连,触发忙线状态 - 所有接收数据全部拼接在内存字符串
data中,大流量场景下内存占用持续飙升,GC卡顿会进一步降低接收处理效率,甚至引发内存溢出 - 没有断连检测和异常捕获逻辑,接收过程中出现任何网络波动都会直接终止程序,没有自动恢复能力
问题解决方案
1. 大流量下断连问题修复
- 优化内存占用:不要全量缓存接收的报文,每接收一段数据就判断
<EOF>标记,匹配到完整报文后立即将业务数据写入磁盘/送入业务处理队列,只保留不完整的报文片段到下一次接收,避免内存持续上涨 - 调整接收模型:将同步接收改为异步回调模式,系统会在有数据到达时自动触发处理逻辑,接收效率远高于同步轮询,适配大流量场景
- 添加TCP保活配置:给Socket开启保活开关,避免空闲连接被设备主动回收
参考优化代码:
private byte[] buffer = new byte[8192]; // 可根据设备单包大小调整缓冲区,建议4k~16k private Socket _sock; private string _unfinishedData = string.Empty; private bool _isReconnecting = false; private const string SERVER_IP = "你的设备IP"; private const int PORT_NO = 你的设备端口; // 初始化Socket连接 private void InitSocket() { IPAddress ipAddress = IPAddress.Parse(SERVER_IP); IPEndPoint deviceEndpoint = new IPEndPoint(ipAddress, PORT_NO); _sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 开启TCP保活,避免空闲断连 _sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); _sock.Connect(deviceEndpoint); // 启动异步接收 StartAsyncReceive(); } // 启动异步接收 private void StartAsyncReceive() { _sock.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null); } // 数据到达自动触发的回调方法 private void ReceiveCallback(IAsyncResult ar) { try { int receivedLength = _sock.EndReceive(ar); if (receivedLength > 0) { string currentSeg = Encoding.ASCII.GetString(buffer, 0, receivedLength); _unfinishedData += currentSeg; // 匹配EOF标记,拆分完整报文 int eofIndex; while ((eofIndex = _unfinishedData.IndexOf("<EOF>")) > -1) { string fullPacket = _unfinishedData.Substring(0, eofIndex); // 此处处理完整报文,建议放入独立队列异步处理,不要阻塞接收线程 ProcessBusinessData(fullPacket); // 保留剩余的不完整报文片段 _unfinishedData = _unfinishedData.Substring(eofIndex + 5); } // 继续监听下一批数据 StartAsyncReceive(); } else { // 设备主动断开连接,触发重连 TriggerReconnect(); } } catch (SocketException) { // 网络异常,触发重连 TriggerReconnect(); } } // 断连重连逻辑 private void TriggerReconnect() { if (_isReconnecting) return; _isReconnecting = true; // 销毁旧Socket资源 try { _sock?.Close(); } catch { } // 间隔1秒再重连,避免频繁请求导致设备忙线 Thread.Sleep(1000); // 重新初始化连接 InitSocket(); _isReconnecting = false; } // 业务数据处理方法,你自己实现 private void ProcessBusinessData(string data) { // 例如写入文件、解析报文等操作 }
2. 自动接收与断连恢复说明
- 自动触发的接收机制:原生Socket没有封装专门的接收事件,但上面代码使用的
BeginReceive异步回调机制完全可以实现同等效果:有数据到达时操作系统会自动触发你注册的ReceiveCallback方法,不需要你主动轮询 - 断连后重新接收:上述代码中的
TriggerReconnect方法已经实现了自动重连逻辑,检测到连接断开、接收异常时会自动销毁旧连接、新建连接并重启接收,无需手动干预。如果需要手动触发重连,直接调用TriggerReconnect方法即可。
内容的提问来源于stack exchange,提问作者Shaiwal Tripathi
相关产品推荐
相关产品推荐

