c#中的socket中的time_wait状态处理方法

本文详细介绍了TCP连接的各种状态,包括LISTENING、ESTABLISHED、CLOSE_WAIT和TIME_WAIT等,并探讨了如何避免TIME_WAIT状态导致的资源浪费问题。此外,还提供了一种特殊的客户端和服务端断开连接的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

端口的状态说明:

TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源不会被释放。网络服务器程序要同时管理大量连接,所以很有必要保证无用连接完全断开,否则大量僵死的连接会浪费许多服务器资源。在众多TCP状态中,最值得注意的状态有两个:CLOSE_WAIT和TIME_WAIT。 
 
1、LISTENING状态
  FTP服务启动后首先处于侦听(LISTENING)状态。

2、ESTABLISHED状态
  ESTABLISHED的意思是建立连接。表示两台机器正在通信。

3、CLOSE_WAIT

    对方主动关闭连接或者网络异常导致连接中断,这时我方的状态会变成CLOSE_WAIT 此时我方要调用close()来使得连接正确关闭

4、TIME_WAIT

    我方主动调用close()断开连接,收到对方确认后状态变为TIME_WAIT。TCP协议规定TIME_WAIT状态会一直持续2MSL(即两倍的分段最大生存期),以此来确保旧的连接状态不会对新连接产生影响。处于TIME_WAIT状态的连接占用的资源不会被内核释放,所以作为服务器,在可能的情况下,尽量不要主动断开连接,以减少TIME_WAIT状态造成的资源浪费。

 

客户端在 设置了

      LingerOption linerOption = new LingerOption(false, 0);

      tcpServer.LingerState = linerOption;

发现还是有time_wait状态

 

在MSDN中 有这样一句话:

           

   Connected 属性获取截止到最后一次 I/O 操作时的 Client 套接字的连接状态。如果该属性返回 false,则表明 Client 要么从未连接,要么已断开连接。

由于 Connected 属性仅反映截止到最近的操作时的连接状态,因此您应该尝试发送或接收一则消息以确定当前状态。当该消息发送失败后,此属性将不再返回 true。注意此行为是设计使然。您无法可靠地测试连接状态,因为在测试与发送/接收之间,连接可能已丢失。您的代码应该假定套接字已连接,并妥善处理失败的传输。

 

因此在客户端发送完成数据后发送完成主体数据之后再通过有限次数循环来向服务端发送断开连接的请求,服务端 在收到后主动先主动关闭连接,之后本端会在某次发送数据过程中抛出异常,通过这个异常 本端再关闭连接,这样可以完全清除tcp中的time_wait状态。否则按照正常流程关闭连接。客户端代码如下:

                 

                   int waitTime = 3;//重试时长
                    totalBytesToSend = AddSendDataLength(isConnected);//结束连接数据
                    while (waitTime > 0)
                    {
                        if (tcpServer.Connected)
                        {
                            //重试三次数据(请求服务端结束连接的数据)的发送,直到(检测到客户端已经断开连接为止,或者检测超出最大检测次数。)
                            sendPoint = 0;//缓存起始发送点
                            curSend = 0;//上一次发送的长度
                           
                            while (sendPoint < totalBytesToSend.Length)
                            {
                                curSend = tcpServer.Client.Send(totalBytesToSend, sendPoint, totalBytesToSend.Length - sendPoint, SocketFlags.None);
                                sendPoint += curSend;
                            }

                            System.Threading.Thread.Sleep(500);//线程阻塞一定时间
                        }
                        else {
                            break;
                        }

                        waitTime--;
                    }
                    tcpServer.Client.Shutdown(SocketShutdown.Both);
                    tcpServer.Client.Close();

### 关于C#TCP Socket优雅关闭 当底层的TCP连接被关闭时,WebSocket连接被认为处于CLOSED状态[^1]。如果在完成WebSocket关闭握手之后TCP连接才被关闭,则认为该WebSocket连接是以清洁方式关闭(cleanly)[^1]。 为了确保在C#中的TCP连接能够以一种不会留下TIME_WAIT状态的方式关闭,在发送FIN标志之前应该先执行一些操作来准备套接字的关闭过程。下面是一个用于展示如何设置并最终关闭一个TCP客户端连接的例子: ```csharp using System; using System.Net.Sockets; public class TcpClientExample { public static void CloseTcpSocketGracefully(TcpClient client) { try { NetworkStream stream = client.GetStream(); // 停止接收数据 client.Client.Shutdown(SocketShutdown.Receive); // 发送任何剩余的数据到服务器端,并停止发送新数据 if (stream.DataAvailable || !client.Client.Poll(0, SelectMode.SelectWrite)) { byte[] buffer = new byte[8192]; int bytesRead; while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0) { Console.WriteLine($"Received {bytesRead} bytes"); } } // 完成写入后调用shutdown方法通知对方不再有更多数据到来 client.Client.Shutdown(SocketShutdown.Send); // 设置linger选项以便立即终止而不等待未确认的数据包返回 LingerOption lingerOption = new LingerOption(true, 0); client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerOption); // 断开连接 client.Close(); } catch (Exception ex) { Console.WriteLine(ex.Message); } } } ``` 上述代码展示了怎样通过`Shutdown()`函数指定只读取或只写入模式下的关闭行为,以及如何配置Linger参数使得本地主机可以快速释放资源而不需要经历完整的四次挥手流程从而避免进入TIME_WAIT状态。 #### 注意事项 - `LingerOption` 的第二个参数设为零意味着一旦应用程序请求关闭socket就会立刻断开连接而不是等待所有待处理的数据都被传输完毕。 - 使用此技术可能会丢失部分已发出但尚未得到确认的数据分组;因此仅适用于那些能够在一定程度上容忍这种损失的应用场景下。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值