TCP连接过程和状态变化
文章目录
TCP建立连接–三次握手
其实TCP建立连接的三次握手网上有很多的啦,下面给出我的理解:
状态解释
CLOSED:虚拟出来的状态,实际不存在,你在netstat -ant | grep 端口的时候是找不到的;
LISTEN:表示Server大门已开,随时准备有Client前来连线;
SYN_SENT:只在Client端出现,表示Client发送过SYN了,正在焦急地等待Server的ACK;
SYN_RCVD:只在Server端出现,表示Server收到Client的SYN了,并且已经发给Client自己的ACK和SYN了,正在焦急地等待Client的ACK;
ESTABLISHED:在Client端出现表示Client把自己的ACK(第3次握手)发出去了,Client已经就绪;在Server端出现表示Server已经收到Client的ACK(第3次握手)了,Server已经就绪;
注:只有在Client和Server同时为ESTABLISHED时,即同时就绪时才可以进行数据传输。
Client端口状态转换
应用层调用connect,发送SYN到对端,等待对端的ACK和SYN;
等待对端的ACK和SYN到来,接收到ACK和SYN后,发出自己的ACK,状态进入ESTABLISHED;
等待对端的ACK和SYN期间,端口状态一直为SYN_SENT,超时后进入CLOSED;
Server端口状态转换
应用层启动侦听,端口进入LISTEN状态;
接收到Client发来的SYN,发送自己的ACK和SYN,进入SYN_RCVD状态,等待Client的ACK;
等待Client的ACK到来,接收到ACK后,进入ESTABLISHED;等待超时,进入CLOSED;
TCP断开连接–四次挥手
TCP通讯双方,不管是Client还是Server,都可以主动断开连接,所以下面我们只以主动方和被动方为标注。(实际情况一般由客户端主动关闭,服务端关闭的也有,看到服务端端口状态为TIME_WAIT时不要奇怪)。
状态解释
FIN_WAIT_1:仅出现在主动方,表示主动方想要断开连接,已经关闭了写通道,并向对端发送了FIN,等待对方的ACK到来;
CLOSE_WAIT:仅出现在被动方,表示被动方收到FIN后,已经回复ACK,正在等自己的应用层调用close方法关闭写通道,在CLOSE_WAIT状态下,自己只能发送数据,但不能接收数据;
FIN_WAIT_2:仅出现在主动方,表示主动方已收到对端的ACK,等待对端的FIN,此时无法再发送数据,但是可以接收数据;
LAST_ACK:仅出现在被动方,表示被动方缓冲区数据已经发送完毕,并且已经发送FIN到对端,等待对端的ACK;如果应用层写的比较垃圾,没有调用close关闭socket,则会一直停留在CLOSE_WAIT;
TIME_WAIT:仅出现在主动方,表示主动方已经发出ACK了,本次通讯完事了,双方都不能再读写了,但是主动方不确定对方能不能收到最后一个ACK,为了保证这个端口释放后,不被后来的连接马上使用被当成是新连接,通俗地讲,为了不乱套,这个状态会一直等待,等多久呢, 等2×MSL(Maximum Segment Lifetime)个时间,这个MSL是操作系统配置的,有默认参数,可以改。
主动方端口状态转换
应用层调用close方法发起关闭连接;
发送FIN到对端,关闭写通道,端口进入FIN_WAIT_1状态;
等待对端的确认ACK到来,接收到ACK后进入FIN_WAIT_2状态;如果在超时时间内没有收到ACK则直接进入CLOSED状态;
如果在FIN_WAIT_1状态时收到了对端的FIN,则进入CLOSING状态
如果在FIN_WAIT_2状态时收到了对端的FIN,则进入TIME_WAIT状态;如果在超时时间内没有收这个FIN则直接进入CLOSED状态;
在TIME_WAIT状态等待2个MSL(报文最长存活周期)后进入CLOSED状态;
被动方端口状态转换
收到对端的FIN后,关闭读通道,自己进入CLOSE_WAIT状态;
在CLOSE_WAIT状态等待应用层调用close方法关闭socket连接;
如果在超时时间内没调用close,则直接进入CLOSED状态;
如果在超时时间内调用了close,则向对端发送FIN,自己进入LAST_ACK状态,等待对端的ACK;
等待对端的ACK,如果在超时时间内收到了ACK则直接进入CLOSED状态,否则超时后进入CLOSED状态;
调优
上边已经提到了,服务端有时也会主动关闭连接,应该是为了避免有些不地道的Client在撩完以后不关闭socket连接,一直占用服务器资源,所以有些服务器也会无情地主动关闭连接,为了自己不被干倒。
在高并发场景下,服务器主动关闭连接的情况,在服务端会出现大量的TIME_WAIT状态的端口,会占用操作系统文件句柄资源,导致新的连接可能无法建立,影响高并发性能,而关于TCP参数的调优中,有一大堆,但有一些参数调优对业务是有风险的,所以这里只给出一个相对比较安全的推荐调优,源自《码出高效 阿里巴巴Java开发手册 终极版 (1.3.0)》。
在Linux服务器上,/etc/sysctl.conf文件中修改time_wait缺省值(默认240秒):
net.ipv4.tcp_fin_timeout = 30
原文链接:https://blog.csdn.net/miss_ruochen/article/details/80782228