C#自定义异步TCP客户端服务器断开后接收回调无限循环问题
问题根因
核心逻辑错误
- TCP协议规定,服务端主动断开连接时,
EndReceive方法会返回0,作为连接关闭的标识 - 现有
ReceiveCallback逻辑中,仅对bytesRead == 0的情况输出警告日志,没有终止接收流程,仍会执行后续的BeginReceive注册新回调 - 此时socket已断开,新注册的接收回调会被立刻触发,形成高速死循环:
EndReceive返回0 → 输出日志 → 注册新接收回调 → 立刻触发回调 → 重复 - 每次循环都会创建新的
StateObject实例,这些实例被异步回调链引用无法被GC回收,直接导致内存指数级上涨。
其他隐藏缺陷
StopAndClean释放socket后未将mpr_clientSocket置空,后续回调会操作已释放的对象- 无并发锁控制,多回调同时操作socket会触发竞态异常
- 析构函数中直接调用
StopAndClean,CLR回收阶段容易访问已释放的非托管对象,触发运行时错误
修复方案
1. 修正接收回调的断开处理逻辑
在ReceiveCallback中,当bytesRead == 0时直接走清理流程,禁止继续注册接收回调:
替换原
bytesRead == 0的分支逻辑:
if (bytesRead > 0) { // 原有接收数据处理逻辑保持不变 } else { OnNewEvent?.Invoke(this, new Event(SOURCE, EventType.Warning, "Remote server closed the connection", "")); StopAndClean(); return; }
2. 完善资源清理逻辑
- 增加锁对象防止并发重复清理
- 释放socket后置空引用,避免悬空操作
// 新增私有锁对象 private readonly object _cleanLock = new object(); private void StopAndClean() { lock (_cleanLock) { if (mpr_clientSocket == null) return; try { if (mpr_clientSocket.Connected) { OnDisconnect?.Invoke(this, EventArgs.Empty); mpr_clientSocket.Shutdown(SocketShutdown.Both); } mpr_clientSocket.Close(); mpr_clientSocket.Dispose(); } catch { /* 忽略清理阶段的异常 */ } finally { mpr_clientSocket = null; mpr_timeoutConnection.Enabled = false; OnNewState?.Invoke(this, TcpClientState.Disconnect); } } }
3. 增加回调前置校验
所有异步回调开头先判断socket状态,已清理则直接返回,避免无效操作:
private void ReceiveCallback(IAsyncResult ar) { // 前置校验,socket已释放则直接退出 if (mpr_clientSocket == null) return; // 原有回调逻辑保持不变 }
内容的提问来源于stack exchange,提问作者Benoit
相关产品推荐
相关产品推荐

