You need to enable JavaScript to run this app. C#自定义异步TCP客户端服务器断开后接收回调无限循环问题
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.05 21:06:03