TcpListener执行AcceptSocket时远程主机关闭TCP连接的原因是什么?
TcpListener.AcceptSocketAsync抛出10054连接重置异常的原因说明
你之前对Accept执行时机的认知存在误差:TCP协议栈处理三次握手的流程和应用层Accept调用是异步的:
- 客户端SYN包到达服务器后,内核先将连接放入半连接队列(SYN队列),返回SYN+ACK给客户端,此时Accept方法不会返回
- 收到客户端的ACK完成三次握手后,内核将连接移入全连接队列(Accept队列),等待应用层调用Accept类方法取走
- 只有你调用
AcceptSocketAsync时,内核才会从全连接队列取出已完成握手的连接返回给应用层
当已经完成三次握手、进入全连接队列的连接,在被应用层取走之前收到了客户端发来的RST包,内核就会在你调用
AcceptSocketAsync时直接返回10054错误,不会返回可用的Socket实例,这就是你遇到的情况。
常见触发场景
- 客户端网络突然中断:三次握手完成后,客户端还没发送任何应用层数据就出现断网、进程崩溃等情况,操作系统自动发送RST包终止连接,此时连接还在全连接队列中未被取走
- 客户端主动提前断开:客户端逻辑异常,三次握手完成后立刻调用关闭逻辑、或者进程直接退出,操作系统会为未处理的活跃连接发送RST包
- 中间网络设备干预:防火墙、负载均衡等网关设备检测到连接完成握手后长时间没有应用层数据交互,主动发送RST切断空闲连接
处理方案
该异常属于TCP网络通信的常规边缘场景,不会影响服务正常运行,只需在Accept循环中捕获该类网络异常,跳过错误继续监听即可,这也是你之前监听循环停止的核心原因:未捕获该异常导致整个循环被中断退出。
推荐的监听循环代码示例:
// 监听服务运行标识 bool isServerRunning = true; TcpListener listener = new TcpListener(IPAddress.Any, 443); listener.Start(); while (isServerRunning) { try { Socket clientSocket = await listener.AcceptSocketAsync(); // 异步处理客户端逻辑,避免阻塞监听循环 _ = HandleClientConnectionAsync(clientSocket); } catch (SocketException ex) when (ex.ErrorCode is 10054 or 10053 or 10061) { // 忽略连接建立阶段的临时网络异常,继续下一次监听 continue; } catch (Exception ex) { // 此处处理监听端口占用、权限不足等致命错误,按需决定是否终止服务 Log.Error(ex, "监听服务发生未知异常"); isServerRunning = false; } }
内容的提问来源于stack exchange,提问作者uriDium
相关产品推荐
相关产品推荐

