本文共 2887 字,大约阅读时间需要 9 分钟。
这幅图是TCP的状态机,看了2个小时,分析总结如下:
(1)CLOSED 状态时初始状态。
(2)LISTEN:被动打开,服务器端的 状态变为LISTEN(监听)。被动打开的概念:连接的一端的应用程序通知操作系统,希望建立一个传入的连接。这时候操作系统为连接的这一端建立一个连 接。与之对应的是主动连接:应用程序通过主动打开请求来告诉操作系统建立一个连接。
(3)SYNRECVD:服务器端收到SYN后,状态为SYN;发送SYN ACK;
(4) SYN_SENTY:应用程序发送SYN后,状态为SYN_SENT;
(5)ESTABLISHED:SYNRECVD收到ACK后,状态为ESTABLISHED; SYN_SENT在收到SYN ACK,发送ACK,状态为ESTABLISHED;
(6)CLOSE_WAIT:服务器端在收到FIN后,发送ACK,状态为CLOSE_WAIT;如果此时服务器端还有数据需要发送,那么就发送,直到数据发送完毕;此时,服务器端发送FIN,状态变为LAST_ACK;
(7)FIN_WAIT_1:应用程序端发送FIN,准备断开TCP连接;状态从ESTABLISHED——>FIN_WAIT_1;
(8)FIN_WAIT_2:应用程序端只收到服务器端得ACK信号,并没有收到FIN信号;说明服务器端还有数据传输,那么此时为半连接;
(9)TIME_WAIT:有两种方式进入 该状态:1、FIN_WAIT_1进入:此时应用程序端口收到FIN+ACK(而不是像FIN_WAIT_2那样只收到ACK,说明数据已经发送完毕)并 向服务器端口发送ACK;2、FIN_WAIT_2进入:此时应用程序端口收到了FIN,然后向服务器端发送ACK;TIME_WAIT是为了实现TCP 全双工连接的可靠性关闭,用来重发可能丢失的ACK报文;需要持续2个MSL(最大报文生存时间):假设应用程序端口在进入TIME_WAIT后,2个 MSL时间内并没有收到FIN,说明应用程序最后发出的ACK已经收到了;否则,会在2个MSL内在此收到ACK报文;
2011.9.14补充:
关闭的状态转换比较复杂:现在设通信双方是A,B,A是主动发起关闭方
(1) 主动发起关闭方:
A首先主动发起FIN报文,准备关闭TCP连接,然后进入FIN_WAIT1状态;然后,如果A收到了ACK报文,就进入FIN_WAIT2状态;而如果A收到的是ACK + FIN,A进入TIME_WAIT状态。
进入FIN_WAIT2状态,说明B还有数据发给A。过了不久之后,B发送FIN给A,然后,A发送ACK,并进入TIME_WAIT状态。当2个MSL内,没有收到FIN信号,那么TIME_WAIT就自动转化为CLOESD。(为什么TIME_WAIT状态要进过2个MSL(Maximum Segment Lifetime.)才能进入CLOSED状态?假设网路是不可靠的,最后A发出的ACK信号丢失,那么B就没有收到ACK,此时B还需要重新发一个FIN给A,这个过程最多需要2MSL,所以如果过了2MSL,没有再次收到B的FIN,那么,说明之间A发出的ACK被B收到了,所以可以可靠地关闭连接。)
(2) 被动接收方
B在收到A的FIN报文后,知道A准备关闭 TCP连接了(注意只是A单方面关闭,也就是说,A还可以收数据,但是不准备发数据了)。B将发送ACK给A,然后B进入CLOSED_WAIT状态。如 果此时B也有数据发送给A,那么就一直发送好了,反正A不会发数据了。此时A处于FIN_WAIT2状态。当B的数据发送完毕之后,那么B发送FIN给 A,B进入LAST_ACK状态。当收到A发过来的ACK信号后,A进入CLOSED状态。
问题:
1、 为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在 一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以 未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报 文和FIN报文多数情况下都是分开发送的。
TCP的关闭连接的时候,状态很多,以刚才的例子分类:一个是主动发起方涉及的状态,一个被动发起方涉及的状态:
主动发起方:
FIN_WAIT1(发出FIN信号)
FIN_WAIT2(收到ACK信号)
TIME_WAIT(收到FIN信号)
CLOSED(2个MSL后,没有再次收到FIN,进入)
被动接收方:
CLOSED_WAIT(收到FIN信号)
LAST_ACK(发出FIN信号)
CLOSED(收到ACK信号,如果没有,再次发出FIN信号)2.为什么能三次握手、四次挥手可靠地建立关闭连接?
注意可靠。
答:在建立连接的时候,首先需要发起方发出请求(即发出带有SYN的报文),接收方收到后必须给发起方一个回应(ACK+SYN)
,关键是这里还没有完毕。因为网络是不可靠地,(a)如果发起方没有收到应答方的ACK+SYN报文,显然,说明报文丢失,必须重发请求;(b)如果发起方收到ACK+SYN后,不再向接收方发出ACK信号(更正于2011.9.17)(也 就是只有两次握手,此时开始传递报文),那么从发起方的角度来看,它认为自己发出的ACK+SYN报文丢失了,接收方没有收到,所以它会再次重发。(c) 当发起方发出ACK信号后,如果没有收到接收方再次发来的ACK+SYN报文,那么说明接收方收到了自己发出的ACK报文,所以可以建立连接了。
举个例子,如何保障可靠通信:
现在A和B两支军队准备在10:00同时发起进攻,如何才能保证这两支军队同时呢?
现在A发出电报,“要求在10:00同时发起进攻”;
B收到后,显然必须向A回复“收到,可以”。
A在收到“收到,可以”的消息后,直到B已 经收到了自己发出的消息。注意,这里还没有完,如果你站在B的角度去思考:“我发出了‘收到,可以’的消息,必须要求A给我一个回应。如果我没有收到回 应,那么就说明我的这个消息没有送到A那里去”,那么,我得再传一次“收到,可以”的消息跟A。所以,A必须再次发出“你的消息已经收到”的消息发送给 B。此时,如果A没有再次收到B发来的“收到,可以”的消息,就可以认为自己的“你的消息已经收到”送给了B。而实际上,如果B收到A发来的“你的消息”我已经收到,说明,自己此前发出的消息已经被A收到。
这样,就可以保证A,B可靠地收到消息,保证他们在10:00准时发起进攻。