建立一个连接需要彼此传递三个数据段的三次握手过程,而终止一个连接要经过彼此发送四个数据段的四次挥手过程。之所以采用“四次挥手”,这是考虑到TCP的半关闭(Half-close)而制定的。由于TCP连接是全双工方式的,因此每个方向都必须单独关闭。其原则是,当一方完成它的数据发送任务后就能发送一个FIN数据段来终止这个方向的连接。收到一个FIN只意味着这一个方向上没有数据流动,一个TCP连接在一方收到一个FIN后仍能发送数据。
下面介绍一下释放建立的四次挥手过程。
率先进行关闭活动的一方将执行主动关闭,而另一方执行被动关闭。下面以客户端主动关闭连接为例解释四次挥手过程,如图5-21所示。
图5-21 “四次挥手”过程示意
第一次挥手。某个应用进程客户端首先调用CLOSE,称该端执行“主动关闭”(Active Close)。该端的TCP处理程序需要发送一个FIN报文段,表示数据发送完毕,请求关闭。这样的报文,除了正常的自己的序号、确认号等信息外,关键要将FIN位设置为1。另外,为了后面说明的方便,设其序号为u,即FIN=1;seq=u。
第二次挥手。服务端接收到这个FIN报文段,执行“被动关闭”(Passive Close)。它需要发回一个ACK,表示自己收到了对方的关闭连接请求数据段。这个表示接收确认的数据段当然也会有自己的序号,但在这个挥手过程中并没有更多的意义,即ACK=1,ack=u+1。
收到FIN,也将作为一个文件结束符(End-of-File)传递给接收端应用进程,放在已排队等候该应用进程接收的任何其他数据之后。因为FIN的接收意味着接收端应用进程在相应连接上再无额外数据可接收。
此时,对被动关闭方来说,虽然已经不会有数据再传递过来了,但自己可能还有要传输的数据,可以继续传输。
第三次挥手。服务器程序数据传输完毕,将要断开此方向上的连接。它也需要发送一个FIN报文段到客户端。这个报文段的FIN位需要设置为1;它需要表示,自己的这个关闭操作是和对方第一次握手的关闭操作相对应的,是对那个FIN包的确认与回应;这个数据段也会有自己的序号,设为w,即FIN=1;ACK=1,ack=u+1;seq=w。
第四次挥手。客户端接收最终的FIN,也要回复一个确认数据段,即ACK=1,ack=w+1。
TCP断开连接,每个方向都需要一个FIN和一个ACK,因此通常需要4个报文段。某些情况下,第一次握手中的FIN随数据一起发送,另外,第二次握手和第三次握手发送的报文段都出自执行被动关闭那一端,有可能被合并成一个报文段。
在第二次握手和第三次握手之间,从执行被动关闭一端到执行主动关闭一端,流动数据是可能的,这称为“半关闭”(Half-Close)。
无论是客户还是服务器,任何一端都可以执行主动关闭。通常情况是,客户执行主动关闭,但是某些协议如HTTP/1.0却由服务器执行主动关闭。
TCP连接时的各种状态表示如下:
FIN-WAIT-1:等待远程TCP连接中断请求,或先前的连接中断请求的确认。FINWAIT-1和FIN-WAIT-2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN-WAIT-1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时SOCKET即进入FIN-WAIT-1状态。当对方回应ACK报文后,则进入FIN-WAIT-2状态。当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN-WAIT-1状态一般是比较难见到的,而FIN-WAIT-2状态常常可以看到。(www.xing528.com)
FIN-WAIT-2:从远程TCP等待连接中断请求。实际上,在FIN-WAIT-2状态下的SOCKET表示半连接,也即有一方要求关闭连接,但另外还告诉对方,我暂时还有一些数据需要传送给你,稍后再关闭连接这就是著名的半关闭的状态了,这是在关闭连接时,客户端和服务器两次握手之后的状态。在这个状态下,应用程序还有接收数据的能力,但是已经无法发送数据;但是也有一种可能是,客户端一直处于FIN-WAIT-2状态,而服务器则一直处于WAIT-CLOSE状态,而直到应用层来决定关闭这个状态。
CLOSE-WAIT:等待从本地用户发来的连接中断请求。这种状态的含义其实是表示在等待关闭。因为,当对方关闭一个SOCKET后发送FIN报文给自己,自己则马上回应一个ACK报文给对方,此时则进入CLOSE-WAI状态。接下来,实际上你真正需要考虑的事情是查看你是否还有数据发送给对方,如果没有,那么你也就可以关闭这个SOCKET,发送FIN报文给对方,即关闭连接。所以在CLOSE-WAIT状态下,需要完成的事情是等待关闭连接。
CLOSING:等待远程TCP对连接中断的确认。
LAST-ACK:等待原来的发向远程TCP的连接中断请求的确认。它被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文时,即可以进入CLOSED状态了。
TIME-WAIT:等待足够的时间以确保远程TCP接收到连接中断请求的确认。表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态。如果在FIN-WAIT-1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入TIME-WAIT状态,而不需要经过FIN-WAIT-2状态。
注意:如果在TCP中处于LAST-ACK状态的连接,如果一直收不到对方的最后一个ACK,那么TCP怎么处理这种情况呢?
假如A是客户端,主动发起关闭,B是服务端。断开连接的前两次挥手均已完成,正常情况下,B开始在此方向上断开连接,发送FIN,进入LAST-ACK状态,A收到这个FIN报文后发送ACK报文,B收到这个ACK报文,然后进入CLOSED状态,但如果B发送FIN,进入LAST-ACK状态,A收到这个FIN后发送ACK报文,由于某种原因,这个ACK报文丢失了,B没有收到ACK报文。此时,B将等待ACK报文超时,然后又向A重传FIN报文。此时,A可能处于如下几种状态,将产生不同的处理方法。
假如这个时候,A还是处于TIME-WAIT状态(也就是TIME-WAIT持续的时间在2MSL内),A收到这个FIN报文后向B发送了一个ACK报文,B收到这个ACK包,进入CLOSED状态。
假如这个时候,A已经从TIME-WAIT状态变成了CLOSED状态,在A收到这个FIN包后,认为这是一个错误的连接,向B发送一个RST包,当B收到这个RST包,进入CLOSED状态。
假如这个时候,A机器出现异常关机或死机等状态,B无法收到A的ACK,那么会继续重传FIN报文,也就是触发了TCP的重传机制;如果A还是没有回应,B还会继续重传FIN报文,直到重传超时,B重置这个连接,再进入CLOSED状态。
注意:必须等待2MSL的时间。
第一,为了保证A发送的最后一个ACK报文段能够到达B。
第二,防止“已失效的连接请求报文段”出现在本连接中。A在发送完最后一个ACK报文段后,再经过时间2MSL,就可以使本连接在持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。
【注释】
[1]在TCP的“固定首部”中,“接收窗口”字段为16 bit,只能用这16 bit表示接收窗口大小。在“扩展首部”的“窗口扩大选项”中,一个字节叫作“移位值”,简称“S”。表示另外两个字节的“窗口扩展数据”在处理时左移的位数。对于任意给定的S值,有(16+S)bit表示接收窗口大小。S的最大取值为14。当其取最大值时,可以用30 bit表示窗口大小。1 Gb大小的接收窗口足以应付当下的网络传输需求。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。