近日无意间发现了一个小窍门:当TCP连接所对应socket的接收队列中仍有未读数据时,将此socket强行close后,将使此socket连接不会进入TIME_WAIT状态,用"netstat -anp"命令查看可发现此连接将消失的无影无踪!上述情形在linux 2.6.18-5-686-bigmem内核及winxp平台上验证通过。其他平台上,以及当socket的发送队列中仍有剩余数据未发送时强行close后是否可重现此现象,尚未进行验证。
那么说了这么多,这个窍门有什么用呢?对TCP的socket编程比较认识的人都知道,通常情况下,当一个socket已成功地在服务端和客户端建立连接后,无论是哪一方,先行调用close的那一方所对应的socket最终必会进入TIME_WAIT状态,并且会持续2*MSL,大约1-4分钟,然后由操作系统自动回收并将TCP连接设为CLOSED初始状态。
在socket的TIME_WAIT状态结束之前,该socket所占用的本地端口号将一直无法释放。编写过高TCP并发并且采用短连接方式进行通讯的软件程序的人,都可能体会到,这样的通讯系统在高并发高负载下运行一段时间后,就经常会出现做为客户端的程序无法向服务端建立新的socket连接的情况。此时用"netstat -anp"命令查看系统将会发现机器上存在大量处于TIME_WAIT状态的socket连接,并且占用大量的本地端口号。最后,当该机器上的可用本地端口号被占完,而旧的大量处于TIME_WAIT状态的socket尚未被系统回收时,就会出现无法向服务端创建新的socket连接的情况。此时的通讯系统几乎停转,空有再好的性能也发挥不出来。
假如能够在客户端程序主动关闭socket之前,让该socket的接收队列中仍保留一些数据(至少要有多余的一个字节的数据),然后调用close关闭,那么上述的无法向服务端创建新的socket连接的情况将不会出现。这是因为当socket的接收队列中仍有数据未被应用程序读走就被强行关闭时,操作系统(至少在笔者验证过的操作系统上的确如此)的TCP/IP协议栈驱动程序会在底层主动向服务端发送一个要求结束TCP连接的控制包,并将该TCP包头的flag控制字段中的RESET位置位,从而迅速结束了此TCP连接。这其实是操作系统对TCP连接断开的一种异常
处理。而正常情况下(socket的接收队列中无未读数据),当应该程序调用close关闭连接时,底层驱动程序向服务端发送的要求结束TCP连接的控制包头的flag控制字段中是将FIN位置位,并最终到达TIME_WAIT状态并持续2*MSL的时间。
知道了上述原理,详细如何利用呢?这有两种思路。
第一种,从服务端入手,在服务端向客户端返回所有有效数据后,再在后面插入若干填充字节;而在客户端将有效数据读完之后,将填充字节留在对应socket的接收队列中,然后直接关闭连接。这个思路的好处是对客户端程序不需要做改动。
第二种思路是从客户端入手,在客户端程序中控制从socket的接收队列中recv数据的节奏,将最后一个有效字节留在接收队列中不取出。但是怎么知道哪里是最后一个字节呢?最后一个字节的内容是什么?解决第一个问题的方法就是制定客户端与服务端通讯协议时应该考虑提供某种机制,让客户端解包时能够知道数据包何时结束,例如可以在通讯包的头部指示整个包的长度。解决第二个问题的方法是调用recv时使用MSG_PEEK标志,例如:
ssize_t recvBytes = recv(socketbufbuflenMSG_PEEK);
当以MSG_PEEK标志接收数据时,数据将只从socket的接收队列中拷贝到指定的buf中,而相应的数据不会被移出接收队列。这样就能够既获得应用程序所需数据,又能将数据留在socket接收队列中,进而能够在关闭时使该TCP连接不进入TIME_WAIT状态。第二种思路的好处是不需要对服务端程序进行改动。笔者已将第二种思路实现并验证可行。
备注:在网上,解除TIME_WAIT状态限制有多种方法,其中有种方法是在socket建立后调用setsockopt函数如下:
int option = 1;
setsockopt(socket SOL_SOCKET SO_REUSEADDR &option sizeof(option));
如此就可以解决问题了。但实际上,有的平台不支持setsockopt函数,既使是在能够支持的平台,笔者经实际验证发现并不能达到目的。另有一些其他方法也各有利弊。所以,如果其他方法无效,本文中的方法就值得一试了。
分享到:
相关推荐
近期服务器出现大量time_wait的TCP连接造成服务器连接数过多而最终导致tomcat假死状态。连接服务器查看连接数的时候提示如下。 [root@test apache-tomcat-7.0.53]# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a...
LINUX 大量TIME_WAIT状态的连接解决方法
tcp连接是网络编程中最基础的概念,基于不同的使用场景,我们一般区分为“长连接”和“短...长短连接的优点和缺点这里就不详细展开了,有心的同学直接去google查询,本文主要关注如何解决tcp短连接的TIME_WAIT问题。
TIME_WAIT状态的意义: 客户端与服务器端建立TCP/IP连接后关闭SOCKET后,服务器端连接的端口 状态为TIME_WAIT 是不是所有执行主动关闭的socket都会进入TIME_WAIT状态呢? 有没有什么情况使主动关闭的socket直接...
tcp连接出现close_wait状态?
详细描述TCP的各个状态,初学者可以快速理解掌握tcp状态图
windows 2008 R2解决socket连接不释放补丁包_time-wait过多注册表修改, Windows time_wait过多解决办法解决办法: 修改注册表中的tcpip的TIMEWAIT回收时间属性值,需要重启后生效 在HKEY_LOCAL_MACHINE\SYSTEM...
linux c 网络编程 测试tcp连接的TIME_WAIT状态 非常适合于初学者
使用 TCP 快速回收:TCP 快速回收是一种优化网络性能的方法,可以在系统内核中设置,可以减少 TIME_WAIT 状态的存在时间。 使用网络优化软件:如果想要快速解决问题,可以使用专业的网络优化软件,例如 TCP ...
NULL 博文链接:https://bert82503.iteye.com/blog/2147899
关于系统端口出现CLOSE_WAIT状态的解决方案,讲解明确清晰,值得参考
netstat显示 TIME_WAIT 的原因及解决办法 netstat显示TCP连接进入TIME_WAIT状态的原因及解决办法
摘要视图订阅01.02.03.04.05.06.162149次第9644名99篇1篇0篇30条【Linux网络编程笔记】TCP短连接产生大量TIME_WAIT导
3.3 timestack数据包-Wireshark3.4 内核协议栈相关主要源码Time_wait状态生成及快速回收相关代码:开启timestamps引起的丢
个人简介文章分类全部博文(229)进程间通信(4)版本控制(9)个人计划(2)进程调度(0)文件系统/存储(3)内存管理(12)系统/脚本(3)编程相关(8)攻
1 检测web服务器的链接数量及状态: netstat -ant|awk '{print $5 \t $6}'|grep ::ffff:|sed -e 's/::ffff://' -e 's/:[0-9]*//' |sort|uniq -c| sort -rn|head -10 结果: 122 125.162.71.199 TIME_WAIT 99 79.119...
问题描述:在Linux系统中高并发的Squid服务器,TCP TIME_WAIT套接字数量经常达到两、三万,服务器很...vi /etc/sysctl.conf增加以下几行: 代码如下:net.ipv4.tcp_fin_timeout = 30net.ipv4.tcp_keepalive_time = 1200...
对于服务器挂起中的CLOSE_WAIT & FIN_WAIT2 解决方案。
使用tcp协议连接onenet平台,实现对单片机外设的控制