TCP的11个状态机
- 三次握手
LISTEN
: 等待从对端TCP节点发送来的请求SYN_SENT
:表示TCP已经发送了一个SYN
报文,代表应用程序执行了一个主动打开的操作,并等待对端回应此连接,并完成连接的建立SYN_RECV
:表示在LISTEN
状态的TCP节点收到的对端的SYN
报文,并已经通过发送SYN/ACK
报文做出了响应。并等待对端TCP节点发送一个ACK
,以此完成连接的建立,进入ESTABLISHED
ESTABLISHED
:与对端TCP节点的连接建立完成。数据和报文可以在两个TCP节点之间双向交换
- 四次挥手
FIN_WAIT1
:应用程序关闭了连接。TCP节点发送一个FIN
报文到对端,以此终止本段的TCP连接,并等待对端发送ACK
。这个状态以及接下来的三个状态都与应用程序执行的主动关闭有关FIN_WAIT2
:表示半连接状态,即有一方想要close连接,但是还要告诉另外对方,还有没有传完的数据需要传给你(ACK
),稍后再关闭连接。之前处在FIN_WAIT1
状态的TCP节点收到了来自对端的ACK
。TIME_WAIT
:表示收到了对方的FIN报文
,并且发送了ACK
报文。如果在FIN_WAIT1
状态下收到了FIN
和ACK
的报文时,可以直接进入TIME_WAIT
状态,无需进入FIN_WAIT2
状态CLOSING
:比较少见的一个状态。一般情况下,当发送FIN
报文时,应该先收到对端的ACK
报文,再收到对端的FIN
报文。但是CLOSING
状态表示你发出FIN
报文后,没有收到对方的ACK
,却收到了对端的FIN
。可以想象,如果两端同时close一个socket的话,就发生了同时发送FIN
报文的情况,于是就出现了CLOSING
状态,表示双方都在关闭socketCLOSE_WAIT
:表示正在等待关闭。当发起方准备关闭socket时,给接收方发送FIN
,接收方会回应一个ACK
给发起方,此时就进入了CLOSE_WAIT
状态。如果接收方没有数据发给发起方了,就可以直接close这个socket。并发送FIN
报文给发起方,即关闭连接。CLOSE_WAIT
是等待接收方去关闭连接LAST_ACK
:表示接收方等待发起方发送最后的ACK
报文,当接收到ACK
报文时,即进入CLOSED
状态CLOSED
:表示连接中断
为何需要三次握手?
回答: 防止过期或失效连接又传给了服务端,因而产生错误。如果不使用三次握手,那么只要接收方发出了SYN/ACK
,新的连接就建立了,由于过期或失效的连接没有发出建立连接的请求,于是不会响应接收方,不会发出ACK
,但是接收方会认为新的连接已经建立,并一直等待发起方传输数据,这样接收方的很多资源就拜拜浪费掉了。主要是防止接收方一直等待,浪费资源
为何需要四次挥手?
首先TCP是全双工的协议,那什么是全双工呢?下面是维基百科的解释:
全双工(full-duplex)的系统允许二台设备间同时进行双向数据传输。一般的电话、手机就是全双工的系统,因为在讲话时同时也可以听到对方的声音。全双工的系统可以用一般的双向车道形容。两个方向的车辆因使用不同的车道,因此不会互相影响。
接收到FIN时意味将没有数据再发来,但是还是可以继续发送数据
第一次挥手
主动发起断开的请求FIN,仅仅代表主动方不再发送数据报文,但是还是能接收数据报文
第二次挥手
被动方响应FIN,发送ACK,告知主动方知道你想断开了,这样主动方就不会一直发送断开的请求。
第三次挥手
被动方在处理完数据报文后,发送FIN给主动方,保证数据通信正常可靠。接着进入LAST_ACK(超时等待)阶段。
第四次挥手
主动方发送ACK响应报文,被动方释放链接。
为什么握手是3次,而挥手是4次?
当我们建立连接的时候,SYN和ACK是可以同事发送的。而关闭连接的时候FIN报文只能单独发送,因为客户端发送FIN报文时,服务端可能还在发送数据(全双工协议),所以没办法确定双方的数据传输完毕。只有当数据全部传输完毕了,才能关闭。