以下命令经常用于服务器的日常维护:
netstat-n|awk‘/^ TCP/{ s [ $ nf ] } end { for (ains ) print a,S[a]}
其中$NF表示最后一个字段
例如,将显示以下信息:
TIME_WAIT 814
CLOSE_WAIT 1
FIN_WAIT1 1
ESTABLISHED 634
SYN_RECV 2
LAST_ACK 1
三种常用状态是: ESTABLISHED表示正在通信,TIME_WAIT表示主动关闭,CLOSE_WAIT表示被动关闭。
更具体地说,挥手4次的交互过程如下。
客户端先发送FIN,进入FIN_WAIT1状态
服务端接收FIN,发送ACK,进入CLOSE_WAIT状态,客户端接收此ACK,进入FIN_WAIT2状态
服务端发送FIN,进入LAST_ACK状态
客户端接收FIN,发送ACK,进入TIME_WAIT状态,服务端接收ACK,进入CLOSE状态
客户端TIME_WAIT持续两倍的MSL时间,在linux体系中约为60s,转移到关闭状态
发送ACK后,可以不进入TIME_WAIT而直接设为关闭状态吗? 不,这是因为TCP协议的可靠性。 由于网络原因,ACK的发送可能会失败。 这样的话,被动方会再次重新发送FIN。 此时,如果主动侧为TIME_WAIT状态,则再次发送ACK以保证可靠性。 那么,根据这个说明,可以理解2MSL的时间长度的设定。 MSL是消息的最大生存时间,如果重发,加上一个FIN个ACK,再加上不定期的延迟时间,大致在2MSL的范围内。
如果服务器发生异常,80%的情况有以下两种:
1 .服务器维持了大量的TIME_WAIT状态
2 .服务器保持了大量的CLOSE_WAIT状态
由于linux分配给单个用户的文件句柄有限,因此如果同时保持TIME_WAIT和CLOSE_WAIT状态,则表示相应数量的通道仍然被占用,如果达到字符上限,则处理新请求
1 )服务端的时间等待太多
首先,我将介绍长连接和短连接。 HTTP1.1协议具有连接标头。 连接有两个值:关闭和保持活动。 此标头相当于在服务器端执行请求后,告知服务器端是关闭连接还是保持连接。 如果服务使用短连接,则每当客户端请求时,服务都会主动发送FIN以关闭连接。 最后进入time_wait状态。 在访问数多的web服务器中,可以考虑存在大量的TIME_WAIT状态。 允许服务快速回收TIME_WAIT资源并更改内核参数。
将/etc/sysctl.conf修改如下:
#对于新连接,内核发送的SYN连接请求数不应大于255。 默认值为5,对应于180秒左右的时间
net.ipv4.tcp_syn_retries=2
#net.ipv4.tcp_synack_retries=2
显示启用#keepalive时,TCP发送keepalive消息的频率。 默认值为2小时,更改为300秒
net.IP v4.TCP _ keepalive _ time=1200
net.ipv4.tcp_orphan_retries=3
如果本地请求关闭套接字,则此参数决定了保持双赢- 2状态的时间
net.ipv4.tcp_fin_timeout=30
#表示SYN队列的长度,默认值为1024,队列长度为8192可以增加等待连接的网络连接数。
net.IP v4.TCP _ max _ syn _ backlog=4096
#表示要打开SYN Cookies。 如果发生SYN队列溢出,可以启用和处理cookies以防止少量SYN攻击。 默认值为0,表示关闭
net.ipv4.tcp_syncookies=1
#表示打开重用。 允许将时间等待套接字重用到新的TCP连接。 默认值为0,处于关闭状态
net.ipv4.tcp_tw_reuse=1
#表示打开TCP连接的时间等待套接字的快速回收,默认值为0表示关闭
net.ipv4.tcp_tw_recycle=1
#减少超时前的探测次数
net.IP v4.TCP _ keepalive _ probes=5
#优化网络设备的接收队列
net.core.net dev _ max _ backlog=3000
更改完成后,运行/sbin/sysctl -p使参数生效。
2 ) close_wait
如果仍为CLOSE_WAIT,则在对方关闭连接后,服务器程序本身可能没有发出更多的FIN信号。 常见原因是TCP连接未调用关闭方法。 换句话说,对方的连接关闭后,程序没有检测到,或者忘记了程序需要在这个时候关闭连接,这个资源仍然被程序占用。 服务器内核参数也无法解决这种情况。 服务器对程序侵占的资源没有积极回收的权利。 在一定程度上,操作系统会使用TCP的KeepAlive功能自动清理CLOSE_WAIT连接,除非您中止程序的运行。
但实际上,由于主要是我们的程序代码有问题,通常是以下问题。
当对方调用closesocket时,你的程序
c代码
intnret=recv(s,……;
if(nret==socket_error ) )。
{
//closesocket(s;
返回假;
}很多人都忘记了那个closesocket
如果主动关闭的一方发送FIN要求被动关闭此处,被动关闭此处的TCP将立即响应一个ACK,同时向上的APP应用程序提交一个ERROR
上面的SOCKET的send或recv会导致返回SOCKET_ERROR。 通常,如果在上面返回SOCKET_ERROR后调用closesocket,则被动关闭侧的TCP会发送一个FIN,其状态将转换为LAST_ACK。