关于Socket通讯中的Close_wait状态
文/转 编辑
编者按:使用Socket通讯,有时我们查看端口状态的时候,经常会发现Socket处于close_wait状态,从而影响系统性能,此文或许会给你一些答案。
最近遇到的一个关于socket.close的问题,在某个应用服务器出现的状况(执行netstat -np | grep tcp):
tcp 0
0 10.224.122.16:50158 10.224.112.58:8788
CLOSE_WAIT
tcp 0
0 10.224.122.16:37655 10.224.112.58:8788
CLOSE_WAIT
tcp 1
0 127.0.0.1:32713
127.0.0.1:8080 CLOSE_WAIT
tcp 38 0
10.224.122.16:34538 10.224.125.42:443
CLOSE_WAIT
tcp 38 0
10.224.122.16:33394 10.224.125.42:443
CLOSE_WAIT
tcp 1
0 10.224.122.16:18882 10.224.125.10:80
CLOSE_WAIT
tcp 1
0 10.224.122.16:18637 10.224.125.10:80
CLOSE_WAIT
tcp 1
0 10.224.122.16:19655 10.224.125.12:80
CLOSE_WAIT
........................................
总共出现了200个CLOSE_WAIT的socket.而且这些socket长时间得不到释放.下面我们来看看为什么会出现这种大量socket的CLOSE_WAIT情况
首先我们要搞清楚的是,这个socket是谁发起的,我们可以看到122.16这台机器开了很多端口,而且端口号都很大,125.12
或者125.10上的端口都是很常见服务器端口,所以122.16上这么多CLOSE_WAIT
的socket是由122.16开启的,换句话说这台机器是传统的客户端,它会主动的请求其他机器的服务端口.
要搞清楚为什么会出现CLOSE_WAIT,那么首先我们必须要清楚CLOSE_WAIT的机制和原理.
假设我们有一个client,
一个server.
当client主动发起一个socket.close()这个时候对应TCP来说,会发生什么事情呢?如下图所示.
client首先发送一个FIN信号给server, 这个时候client变成了FIN_WAIT_1的状态, server端收到FIN之后,返回ACK,然后server端的状态变成了CLOSE_WAIT.
接着server端需要发送一个FIN给client,然后server端的状态变成了LAST_ACK,接着client返回一个ACK,然后server端的socket就被成功的关闭了.
从这里可以看到,如果由客户端主动关闭一链接,那么客户端是不会出现CLOSE_WAIT状态的.客户端主动关闭链接,那么Server端将会出现CLOSE_WAIT的状态.
而我们的服务器上,是客户端socket出现了CLOSE_WAIT,由此可见这个是由于server主动关闭了server上的socket.
那么当server主动发起一个socket.close(),这个时候又发生了一些什么事情呢.
从图中我们可以看到,如果是server主动关闭链接,那么Client则有可能进入CLOSE_WAIT,如果Client不发送FIN包,那么client就一直会处在CLOSE_WAIT状态(后面我们可以看到有参数可以调整这个时间).
那么现在我们要搞清楚的是,在第二中场景中,为什么Client不发送FIN包给server.要搞清楚这个问题,我们首先要搞清楚server是怎么发FIN包给client的,其实server就是调用了
socket.close方法而已,也就是说如果要client发送FIN包,那么client就必须调用socket.close,否则就client就一直会处在CLOSE_WAIT。