预计阅读本页时间:-
6.1.2 TCP/IP三次握手的过程详解
1.建立连接协议(三次握手)
1)客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的报文1。
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
2)服务器端回应客户端,这是三次握手中的第2个报文。这个报文同时带有ACK标志和SYN标志,它表示对刚才客户端SYN报文的回应,同时又将标志SYN回传给客户端,询问客户端是否准备好进行数据通信。
3)客户端必须再次回应服务器端一个ACK报文,这是报文3。
说明
报文(message)是网络中交换与传输的数据单元,其中包含了将要发送的完整的数据信息,其长短很不一致。报文又可分为自由报文和数字报文两种。它也是网络传输的单位,会不断地通过封装成分组、包、帧来进行传输,封装的方式就是添加一些信息段,所添加的信息段就是报文头。
2.连接终止协议(四次挥手)
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。原则上是当一方完成它的数据发送任务时就发送一个FIN来终止这个方向的连接。收到一个FIN只意味着这一方向上没有数据流动了,一个TCP连接在收到一个FIN后仍能发送数据。首先关闭的一方将执行主动关闭,而另一方则执行被动关闭。具体步骤如下:
1)TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送(报文4)。
2)服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文5)。和SYN一样,一个FIN将占用一个序号。
3)服务器关闭客户端的连接,发送一个FIN给客户端(报文6)。
4)客户段发回ACK报文确认,并将确认序号设置为收到的序号加1(报文7)。
在TCP三次握手、四次挥手的过程中存在多种TCP连接状态,分别如下。
·CLOSED:这个没什么好说的,表示初始状态。
·LISTEN:这也是非常容易理解的一个状态,表示服务器端的某个Socket正处于监听状态,可以接收连接了。
·SYN_RCVD:这个状态表示接收到了SYN报文,在正常情况下,这个状态是服务器端的Socket在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,用netstat命令基本上是很难看到这种状态的,除非特意编写一个客户端测试程序,故意将TCP三次握手过程中的最后一个ACK报文不予发送。在正常情况下,当收到客户端的ACK报文时,它会进入到ESTABLISHED状态。
·SYN_SENT:这个状态与SYN_RCVD遥相呼应,当客户端Socket执行CONNECT连接时,它首先会发送SYN报文,随即进入SYN_SENT状态,并等待服务端发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送了SYN报文。
·ESTABLISHED:这个很容易理解,表示连接已经建立了。
·FIN_WAIT_1:这个状态要好好解释一下,其实FIN_WAIT_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状态还是常常可以用netstat看到的。
·FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的Socket,表示半连接,即有一方要求关闭连接,同时还会告诉对方,我暂时还有点数据需要传送给你,稍后将关闭连接。
·TIME_WAIT:表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后回到CLOSED可用状态。如果FIN_WAIT_1状态下,收到了对方同时带有FIN标志和ACK标志的报文,就可以直接进入到TIME_WAIT状态了,而无须经过FIN_WAIT_2状态。
·CLOSING:这种状态比较特殊,在实际应用中应该很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文时,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,而是收到了对方的FIN报文。在什么情况下会出现此状况呢?其实细想一下,也不难得出结论:如果双方几乎在同时关闭一个Socket的话,那么就会出现双方同时发送FIN报文的情况,也就会出现CLOSING状态,表示双方都正在关闭Socket连接。
·CLOSE_WAIT:这种状态的含义其实是表示正在等待关闭。怎么理解呢?当对方关闭一个Socket后发送FIN报文给自己,系统会毫无疑问地回应一个ACK报文给对方,此时就会进入到CLOSE_WAIT状态。实际上接下来你真正需要考虑的事情是,查看你是否还有数据要发送给对方,如果没有的话,那么你就可以关闭这个Socket,发送FIN报文给对方,即关闭连接了。所以在CLOSE_WAIT的状态下,需要完成的事情是等待,然后关闭连接。
·LAST_ACK:这个状态还是比较好理解的,它是被动关闭的一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文时,就表示可以进入CLOSED可用状态了。
现在,大家来思考一个问题:为什么TIME_WAIT状态还需要等2MSL(报文最大生存时间)后才能返回到CLOSED状态呢?
答案是虽然双方都同意关闭连接了,而且握手的4个报文也都协调好并发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态一样),但是因为我们必须要假设网络是不可靠的,你无法保证最后发送的ACK报文一定会被对方收到,比如对方正处于LAST_ACK状态下的Socket可能会因为超时未收到ACK报文,这时就需要重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失了的ACK报文的。
希望下面的流程图能够帮助大家理解这个过程,流程图如图6-2所示。
图6-2 TCP/IP三次握手流程图(顺序为NEW→SYN/ACK→ACK)