客户端停止发送数据后TCP连接被强制断开是什么原因?
问题解答
异常触发根本原因
你遇到的报错本质是客户端主动断开了TCP连接,和服务端的ReadTimeout配置无关:
- 你设置的
NetworkStream.ReadTimeout = Infinite仅控制应用层读取操作的最大等待时长,不会干预底层TCP连接的存活状态,也无法阻止对端主动发送RST/FIN包断开连接。 - 你给出的客户端代码中,执行完
Send逻辑后如果没有额外代码保持TcpClient实例的引用,该实例会被.NET垃圾回收器自动回收,回收时会主动销毁底层Socket并向服务端发送RST包,此时服务端阻塞在ReadByte()的调用就会抛出对应异常。垃圾回收的触发间隔通常在几十秒范围,和你遇到的50-60秒断开的现象完全匹配。
关于隐藏超时配置的说明
你场景下的问题和这两类配置无关,仅做补充说明:
- 操作系统自带的TCP保活(KeepAlive)默认关闭,即使开启默认的空闲检测等待时长也在2小时以上,远长于你遇到的1分钟断开周期,可以排除。
- 中间网络设备(防火墙、NAT网关)的空闲连接断开策略仅存在于跨设备通信场景,你使用127.0.0.1本地环回通信,不存在中间设备,可以排除。
修复方案
客户端侧修复
在发送逻辑结束后添加代码保持TcpClient实例的存活,避免被GC回收:
client.Connect("127.0.0.1", portNumber); PacketBuilder builder = new PacketBuilder(); builder.AddOpCode(4); builder.AddByte(4); builder.AddString("Test"); var packet = builder.GetByteArray(); client.Client.Send(packet, packet.Length, SocketFlags.None); // 新增:阻止TcpClient被回收,保持连接存活 while (true) { Thread.Sleep(Timeout.Infinite); }
你也可以将TcpClient声明为全局静态变量,脱离局部作用域回收逻辑。
服务端侧兼容优化
即使客户端正常异常断开,服务端也应该添加异常捕获逻辑,避免单客户端断开导致整个服务异常:
while (isConnected) { try { var packetOpCode = nr.ReadByte(); var packetSize = Constants.INCOMING_SIZES[packetOpCode]; NetPacket packet; /* i.e 127 */ packetSize = nr.ReadByte(); var payload = nr.ReadBytes(packetSize); packet = new NetPacket { OpCode = packetOpCode, Length = packetSize, Payload = payload }; _packets.Add(packet); Console.WriteLine( $"#: {_id} Queue: [{_packets.Count}] - Packet with ID: {packet.OpCode} added. "); File.AppendAllText("Log.txt", $"#: {_id} Queue: [{_packets.Count}] - Packet with ID: {packet.OpCode} added. \n"); } catch (IOException ex) { // 连接断开处理逻辑 isConnected = false; Console.WriteLine($"客户端{_id}已断开连接:{ex.Message}"); // 后续可添加资源释放、日志记录逻辑 } }
内容的提问来源于stack exchange,提问作者Riley Varga
相关产品推荐
相关产品推荐

