TCP
TCP是面向连接的协议,所以TCP运输连接的建立和释放是每次TCP通信中必不可少的过程;
在整个TCP运输连接中存在三个阶段:连接建立、传输数据、连接释放,而计算机系统需要一个管理机制来保证TCP运输连接的建立和释放都能正常的进行,这个管理过程就是通过通信双方在知晓对方存在的情况下,通过一些参数进行协商,运输实体资源;
“三次/四次握手”-TCP连接的建立
假设A是TCP客户,B是TCP服务器
双方先都处于CLOSED状态;
当系统启动后,B作为服务器端开启连接,创建传输控制块TCB,进入并保持LISTEN状态,等待客户端连接请求(此时会对客户端发来的请求做出响应);
在服务端进入LISTEN状态之后,A作为客户端开始它的连接流程,首先同样是创建TCB,此时要向B发送连接请求报文段(SYN);SYN报文段按照TCP规定不包含数据部分,最主要的信息就是其中的两个字段“SYN=1,seq=x(某一个序号值)”;此时A进入SYN-SENT(同步请求已经发送)状态;
这里插一句,在TCP连接不管是建立还是释放的过程中,所发送的报文都要消耗一个序号;唯有一个例外,就是ACK报文段,ACK报文段是允许携带数据的,如果携带数据则消耗序号,如果不携带数据则不消耗
正在LISTEN状态的B接收到A发来的SYN报文之后,需要作出响应,回传一个SYN=1,ACK=1,seq=y(某一个序号值),ack=x+1的请求确认报文(ACK),发送完毕之后B进入SYN-RCVD(received)状态;
SYN=1表示该报文是同步报文,ACK=1表示该报文是对收到报文的确认报文,ack=x+1是因为要回复的报文的seq=x
为什么TCP连接的建立过程又可以叫三次握手又可以叫四次握手呢?因为这一步骤B发送的报文发挥了两个作用,一是确认A发来的连接请求,二是发送从B到A的连接请求;可以说TCP连接全双工的特点在这里体现,一定是AB的双向连接都建立完毕之后整个连接过程才算成功;
但其实我们知道当B回传了SYN之后,A其实已经可以认为反向连接已经建立了,为什么还要再向B发送ACK报文呢?这里引出一个问题
由于B在回复A的连接请求的同时,也发送了从B到A的连接请求,所以A先进入ESTABLISHED(A到B的单向连接已经建立)状态,之后也必须像上一步一样向B发送ACK=1,seq=x+1,ack=y+1的确认报文;
seq=x+1是因为A第一次发送请求报文时seq=x,而TCP连接建立和释放的过程中每发送一个报文都要消耗一个序号;
当B收到A的确认报文之后,说明B到A的单向连接也已经建立完成,此时B也进入ESTABLISHED状态,至此宣告AB之间的TCP连接建立完成;
第三/四次握手的意义
这是为了防止存在A到B的超时的SYN报文,如果它来的很晚,此时A因为长时间没收到B的ACK报文已经进入连接超时异常了,这时B突然又收到了该超时报文并向A发送了SYN+ACK报文,这时B会认为由A到B的连接已经建立了;这就导致了双方的不同步,B会一直等待A,知道B通过重复确认之后主动结束连接才会回到正常流程,这样会导致B浪费了太多的资源;
“四次挥手”-TCP连接的释放
双方都先处于ESTABLISHED状态
上面说到TCP连接是双向全双工的,如果要释放连接的话同样也是先关闭主动方到被动方的连接,然后再关闭反向的连接;
首先A的某个应用请求关闭已经建立的TCP连接,此时A会发送结束报文段(FIN)(同样不携带数据)主要信息有两个字段“FIN=1,seq=u(某一个序号值)”,发送完毕后A就进入到FIN-WAIT-1(主动-被动连接终止等待)状态;
当B受到A的FIN请求之后,则会通知对应应用即将关闭连接,同时向A发送对A的FIN请求确认的ACK报文,其中“ACK=1,seq=v(某一个序号值),ack=u+1”,B此时进入CLOSE-WAIT(关闭等待)状态,此时B仍然可以向A发送数据
CLOSE-WAIT阶段存在的意义就是给B一个上层协议处理时间,将扫尾工作做完,该发的发,该设置的设置;
这里多说一句,在笔者通过查阅资料得知(欢迎大家补充),有两种情况可能会导致一个CLOSE-WAIT时间变得非常长:当服务器端同时响应了过多的连接关闭请求,或者因为其他一些事情导致没来得及响应请求时,这个CLOSE-WAIT的时间就会变长;后一种一般都是程序代码编写问题,要不是服务器端程序未做好close处理,或者程序响应速度太慢;前一种就是没有做好分布处理,响应队列阻塞导致严重超时
当A接收到B的ACK报文之后,A即进入FIN-WAIT-2,此时A到B的连接已经被释放了,并且继续等待B发来的FIN报文;
当B的CLOSE-WAIT阶段结束之后,随即向A发送FIN报文,包含“FIN=1,ACK=1,seq=w,ack=u+1”,告知A:从B到A的连接也即将关闭了,此时B进入LAST-ACK状态,等待A回传最终的确认;
为什么B到A的FIN报文也包含了ACK信息呢?这是因为在这一阶段B仍然可以向A发送数据,所以在数据传输阶段之后,需要通过设置ACK状态值告知A:“连接关闭流程继续”;即seq=w是因为前面还可能发送了其他报文所以才不是v+1,ack=u+1说明该报文仍是对上面步骤2中A发送的FIN报文进行确认;
A接收到B发来的FIN报文之后,即向B发送ACK报文,包含信息“ACK=1,seq=u+1,ack=w+1”,进入TIME-WAIT状态,在这之后A仍需等待2MSL时间才会将传输控制块TCB销毁,进入CLOSED状态,完全结束连接;
这里引出一个问题,为什么要存在TIME-WAIT这个时间段?直接结束连接不好吗?
当B收到最后的ACK报文之后,就会进入进入CLOSED状态,完全结束连接;
TIME-WAIT的意义
首先说明MST一般设置为2m,虽然对现在的网络来说比较长了;
有两个原因:
防止报文丢失
如果LAST-ACK阶段A发出的ACK报文最终并没有传到B,那么B在等待超时之后即会向A发送超时重传上一阶段FIN
+ACK的报文段,同样的以上所提到过的每一阶段如果出现超时问题,都有对应的检测和恢复手段;
当A接收到B的重传之后,会重置2MST计时,并再次发送最后的ACK报文,通过这样的机制保证B能正确进入CLOSED状态;
防止存在超时报文
2MST的时间能保证网络中不再存在超时的连接报文,以避免上述第三/四次握手中出现的问题;
保活计时器
正常进行流程时,每一次成功执行当前步骤都会刷新保活计时器,这个机制有点像嵌入式设计中的watchdog计时器,意义就是保证程序正常执行而不超时,通常设定为2h;
当某一个阶段有客户端出现错误时,整个流程不能再进行下去,一旦计时器归零(2h内都没有收到客户端的消息),服务器端即会每隔75s发送一次探测报文,十次后仍没有回应则会强制终止连接
参考:
《计算机网络(第7版)》 谢希仁 编
关于TCP的CLOSE_WAIT, 你知道多少?
http://baijiahao.baidu.com/s?id=1583638260236071388&wfr=spider&for=pc