TCP的三次握手和四次挥手
今天去面试围绕RPC组件这一块被询问到了TCP的连接机制,脑子仅存在大学里的一点记忆,于是回来整理一番,先看个例子
三次握手:
A:“喂,你听得到吗?”A->SYN_SEND
B:“我听得到呀,你听得到我吗?”应答与请求同时发出 B->SYN_RCVD | A->ESTABLISHED
A:“我能听到你,今天balabala……”B->ESTABLISHED
四次挥手:
A:“喂,我不说了。”A->FIN_WAIT1
B:“我知道了。等下,上一句还没说完。Balabala…..”B->CLOSE_WAIT | A->FIN_WAIT2
B:”好了,说完了,我也不说了。”B->LAST_ACK
A:”我知道了。”A->TIME_WAIT | B->CLOSED
A等待2MSL,保证B收到了消息,否则重说一次”我知道了”,A->CLOSED
问题一:为什么TCP协议终止链接要四次?
1、当主机A确认发送完数据且知道B已经接受完了,想要关闭发送数据口(当然确认信号还是可以发),就会发FIN给主机B。
2、主机B收到A发送的FIN,表示收到了,就会发送ACK回复。
3、但这是B可能还在发送数据,没有想要关闭数据口的意思,所以FIN与ACK不是同时发送的,而是等到B数据发送完了,才会发送FIN给主机A。
4、A收到B发来的FIN,知道B的数据也发送完了,回复ACK, A等待2MSL以后,没有收到B传来的任何消息,知道B已经收到自己的ACK了,A就关闭链接,B也关闭链接了。
问题二:为什么等待2MSL,从TIME_WAIT到CLOSE?
在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。
要点一:三次握手建立连接时,发送方再次发送确认的必要性
主要是为了防止已失效的连接请求报文段突然又传到了B,因而产生错误。假定出现一种异常情况,即A发出的第一个连接请求报文段并没有丢失,而是在某些网络结点长时间滞留了,一直延迟到连接释放以后的某个时间才到达B,本来这是一个早已失效的报文段。但B收到此失效的连接请求报文段后,就误认为是A又发出一次新的连接请求,于是就向A发出确认报文段,同意建立连接。假定不采用三次握手,那么只要B发出确认,新的连接就建立了,这样一直等待A发来数据,B的许多资源就这样白白浪费了。
要点二:四次挥手释放连接时,等待2MSL的意义
第一,为了保证A发送的最有一个ACK报文段能够到达B。这个ACK报文段有可能丢失,因而使处在LAST-ACK状态的B收不到对已发送的FIN和ACK报文段的确认。B会超时重传这个FIN和ACK报文段,而A就能在2MSL时间内收到这个重传的ACK+FIN报文段。接着A重传一次确认。
第二,就是防止上面提到的已失效的连接请求报文段出现在本连接中,A在发送完最有一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。
要点三:TCP的有限状态机
连接的建立和释放所要求的步骤可以用一个有限状态机来表达,该状态机有11种状态。每一种状态中都存在一些合法的事件,当合法事件发生的时候,可能需要采取某个动作。当其他事件发生的时候,则报告一个错误。
状 态 |
描 述 |
CLOSED |
关闭状态,没有连接活动或正在进行 |
LISTEN |
监听状态,服务器正在等待连接进入 |
SYN RCVD |
收到一个连接请求,尚未确认 |
SYN SENT |
已经发出连接请求,等待确认 |
ESTABLISHED |
连接建立,正常数据传输状态 |
FIN WAIT 1 |
(主动关闭)已经发送关闭请求,等待确认 |
FIN WAIT 2 |
(主动关闭)收到对方关闭确认,等待对方关闭请求 |
TIMED WAIT |
完成双向关闭,等待所有分组死掉 |
CLOSING |
双方同时尝试关闭,等待对方确认 |
CLOSE WAIT |
(被动关闭)收到对方关闭请求,已经确认 |
LAST ACK |
(被动关闭)等待最后一个关闭确认,并等待所有分组死掉 |
- 客户进程变迁的过程(粗实线)
-
- 连接建立:设一个主机的客户进程发起连接请求(主动打开),这时本地TCP实体就创建传输控制快(TCB),发送一个SYN为1的报文,进入SYN_SENT状态。当收到来自进程的SYN和ACK时,TCP就发送出三次握手中的最后一个ACK,进而进入连接已经建立的状态ESTABLISHED。
- 连接释放:设运行客户进程主机本地TCP实体发送一个FIN置为1的报文,等待着确认ACK的到达,此时状态变为FIN_WAIT_1。当运行客户进程主机收到确认ACK时,则一个方向的连接已经关闭。状态变成FIN_WAIT_2。当运行客户进程的主机收到运行服务器进程的主机发送的FIN置为1的报文后,应响应确认ACK时,这是另一个连接关闭。但此时TCP还要等待一段时间后才删除原来建立的连接记录。返回到初始的CLOSED状态,这是为了保证原来连接上的所有分组都从网络中消失了。
- 服务器进程变迁的过程(粗虚线)
-
- 连接建立:服务器进程发出被动打开,进入监听状态LISTEN。当收到SYN置为1的连接请求报文后,发送确认ACK,并且报文中的SYN也置为1,然后进入SYN_RCVD状态。在收到三次握手最后一个确认ACK时,就转为ESTABLISHED状态。
- 连接释放:当客户进程的数据已经传送完毕。就发出FIN置为1的报文给服务器进程,进入CLOSE_WAIT状态。服务器进程发送FIN报文段给客户进程,状态变为LAST_ACK状态。当收到客户进程的ACK时,服务器进程就释放连接。删除连接记录。回到原来的CLOSED状态。