You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure负载均衡下C# SocketAsyncEventArgs客户端断开检测问题

问题描述

实现TCP服务端与客户端连接时,遇到一个本地可复现但服务器(部署在Azure负载均衡器下)持续存在的问题:当客户端断开Wi-Fi后,服务端无法检测到TCP连接已断开,也就无法执行断开后的处理逻辑。

已尝试的方案均无效:

  1. 每5秒发送心跳消息,使用SocketAsyncEventArgs实现,但SendAsync并未如文档所述在Socket关闭时抛出ObjectDisposedException,且SendAsync成功不代表数据送达,无法用于检测连接状态。代码如下:
_socketAsyncEvent = new SocketAsyncEventArgs();
_socketAsyncEvent.Completed += OnSendCompleted;

public void SendHeartbeat() {

  byte[] message = ...;
  _socketAsyncEvent.SetBuffer(message, 0, message.Length);

  if (!_connection.Socket.SendAsync(_socketAsyncEvent))
  {
     OnSendCompleted(this, _socketAsyncEvent);
  }
}

protected void OnSendCompleted(object? sender, SocketAsyncEventArgs e)
{
   _socketAsyncEvent.SetBuffer(null, 0, 0);
}
  1. 使用!(Socket.Poll(100, SelectMode.SelectRead) && Socket.Available == 0)检测,返回结果始终为true,无法判定连接状态。
  2. 本地环境中可通过接收结果的BytesTransferred为0判断连接关闭,但服务器上未出现该情况。

需要了解:在Azure负载均衡器部署环境下,还有哪些方法可以从服务端判断TCP连接已断开?


解决方案

针对Azure负载均衡器下的TCP连接检测问题,可尝试以下几种可靠方法:

  • 启用系统级TCP Keep-Alive
    底层TCP Keep-Alive是最稳定的连接检测方式,Azure负载均衡器会响应这些探测包。在C#中通过Socket.IOControl配置:

    const int SIO_KEEPALIVE_VALS = 0x98000004;
    byte[] keepAliveConfig = new byte[12];
    // 开启Keep-Alive
    BitConverter.GetBytes(1).CopyTo(keepAliveConfig, 0);
    // 5秒后发起第一次探测
    BitConverter.GetBytes(5000).CopyTo(keepAliveConfig, 4);
    // 每次探测间隔1秒
    BitConverter.GetBytes(1000).CopyTo(keepAliveConfig, 8);
    
    _connection.Socket.IOControl(SIO_KEEPALIVE_VALS, keepAliveConfig, null);
    

    客户端断开后,系统会自动发送探测包,多次失败后标记Socket为断开状态,后续Send/Receive操作会抛出异常或返回0字节。

  • 实现带响应校验的应用层心跳
    单纯发送心跳包无法确认客户端存活,需增加客户端响应机制:

    1. 服务端每5秒发送心跳请求包;
    2. 为每个连接维护心跳超时计数器,收到客户端响应时重置计数器;
    3. 若计数器超过阈值(如15秒,即3次心跳未响应),主动关闭Socket并执行断开处理逻辑。
      这种应用层心跳不受底层TCP状态和负载均衡器的限制,可靠性更高。
  • 检查SocketAsyncEventArgs的错误状态
    在OnSendCompleted方法中,必须校验e.SocketError属性。即使SendAsync未抛出异常,连接断开时该属性会返回ConnectionReset、NotConnected等错误码:

    protected void OnSendCompleted(object? sender, SocketAsyncEventArgs e)
    {
       if (e.SocketError != SocketError.Success)
       {
           // 连接已断开,执行清理逻辑
           HandleConnectionDisposal();
       }
       _socketAsyncEvent.SetBuffer(null, 0, 0);
    }
    
  • 调整Azure负载均衡器的空闲超时
    Azure负载均衡器默认TCP空闲超时为4分钟,若心跳间隔(5秒)小于该值,负载均衡器会保持连接,但客户端断开后可能不会立即通知服务端。可在Azure门户调整空闲超时:

    • 标准负载均衡器可设置为30秒至30分钟;
    • 确保超时时间大于心跳间隔,同时让负载均衡器在连接空闲超时后主动关闭连接,服务端即可检测到断开状态。

内容的提问来源于stack exchange,提问作者Anna Melashkina

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 23:05:32