C# TcpClient设置LingerOption调用Close仍出现TIME_WAIT导致重连异常
问题根因分析
- TcpClient实例复用逻辑错误
调用TCPSocket.Close()后,实例底层Socket资源已被释放,该实例不可再用于发起新连接,直接调用第二次Connect()必然抛出异常。
- TcpClient实例复用逻辑错误
- LingerOption配置未生效
你在关闭连接前先调用了Shutdown(SocketShutdown.Both),该操作会触发正常的TCP四次挥手流程,此时后续执行的Close()会忽略Linger配置,按正常流程断开,主动断开方就会进入TIME_WAIT状态。
- LingerOption配置未生效
- ReuseAddress配置未生效
你仅在首次初始化TcpClient时配置了ReuseAddress,第二次重连没有重新实例化TcpClient并重新配置该参数,且旧实例资源已释放,配置无法作用于新的连接请求。
- ReuseAddress配置未生效
修复方案
方案1:无需固定本地端口(推荐,无端口冲突问题)
如果业务没有要求必须使用本地50010端口发起连接,直接让系统自动分配空闲本地端口,从根源避免TIME_WAIT导致的端口占用问题:
while (true) { // 每次重连都实例化新的TcpClient,不指定本地端口,系统自动分配 using var TCPSocket = new TcpClient(); TCPSocket.ReceiveTimeout = 5000; // 发起连接 TCPSocket.Connect(new IPEndPoint(IPAddress.Parse("10.10.0.50"), 50010)); // 执行业务逻辑 // Do something // 关闭连接 TCPSocket.Client.Shutdown(SocketShutdown.Both); TCPSocket.Close(); // 等待10秒后重连 Thread.Sleep(10000); }
方案2:必须固定本地50010端口
如果业务要求必须使用本地50010端口发起连接,调整配置和关闭逻辑,让LingerOption生效跳过TIME_WAIT:
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse("10.10.0.100"), 50010); IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse("10.10.0.50"), 50010); while (true) { // 每次重连都实例化新的TcpClient using var TCPSocket = new TcpClient(); // 先配置参数再绑定端口 TCPSocket.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); TCPSocket.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, new LingerOption(true, 0)); // 绑定本地端口 TCPSocket.Client.Bind(localEndPoint); // 发起连接 TCPSocket.Connect(remoteEndPoint); TCPSocket.ReceiveTimeout = 5000; // 执行业务逻辑 // Do something // 注意:不要先调用Shutdown,直接Close触发Linger配置,发送RST包跳过四次挥手,避免TIME_WAIT TCPSocket.Close(); // 等待10秒后重连 Thread.Sleep(10000); }
注意:使用Linger(true,0)强制断开会导致未发送完的数据直接丢失,确保业务逻辑执行完成后所有数据都已发送完成再调用Close。
内容的提问来源于stack exchange,提问作者Triplehoon
相关产品推荐
相关产品推荐

