TCP的11个状态机

  • 三次握手
  1. LISTEN: 等待从对端TCP节点发送来的请求
  2. SYN_SENT:表示TCP已经发送了一个SYN报文,代表应用程序执行了一个主动打开的操作,并等待对端回应此连接,并完成连接的建立
  3. SYN_RECV:表示在LISTEN状态的TCP节点收到的对端的SYN报文,并已经通过发送SYN/ACK报文做出了响应。并等待对端TCP节点发送一个ACK,以此完成连接的建立,进入ESTABLISHED
  4. ESTABLISHED:与对端TCP节点的连接建立完成。数据和报文可以在两个TCP节点之间双向交换

  • 四次挥手
  1. FIN_WAIT1:应用程序关闭了连接。TCP节点发送一个FIN报文到对端,以此终止本段的TCP连接,并等待对端发送ACK。这个状态以及接下来的三个状态都与应用程序执行的主动关闭有关
  2. FIN_WAIT2:表示半连接状态,即有一方想要close连接,但是还要告诉另外对方,还有没有传完的数据需要传给你(ACK),稍后再关闭连接。之前处在FIN_WAIT1状态的TCP节点收到了来自对端的ACK
  3. TIME_WAIT:表示收到了对方的FIN报文,并且发送了ACK报文。如果在FIN_WAIT1状态下收到了FINACK的报文时,可以直接进入TIME_WAIT状态,无需进入FIN_WAIT2状态
  4. CLOSING:比较少见的一个状态。一般情况下,当发送FIN报文时,应该先收到对端的ACK报文,再收到对端的FIN报文。但是CLOSING状态表示你发出FIN报文后,没有收到对方的ACK,却收到了对端的FIN。可以想象,如果两端同时close一个socket的话,就发生了同时发送FIN报文的情况,于是就出现了CLOSING状态,表示双方都在关闭socket
  5. CLOSE_WAIT:表示正在等待关闭。当发起方准备关闭socket时,给接收方发送FIN,接收方会回应一个ACK给发起方,此时就进入了CLOSE_WAIT状态。如果接收方没有数据发给发起方了,就可以直接close这个socket。并发送FIN报文给发起方,即关闭连接。CLOSE_WAIT是等待接收方去关闭连接
  6. LAST_ACK:表示接收方等待发起方发送最后的ACK报文,当接收到ACK报文时,即进入CLOSED状态
  7. CLOSED:表示连接中断

为何需要三次握手?

回答: 防止过期或失效连接又传给了服务端,因而产生错误。如果不使用三次握手,那么只要接收方发出了SYN/ACK,新的连接就建立了,由于过期或失效的连接没有发出建立连接的请求,于是不会响应接收方,不会发出ACK,但是接收方会认为新的连接已经建立,并一直等待发起方传输数据,这样接收方的很多资源就拜拜浪费掉了。主要是防止接收方一直等待,浪费资源

为何需要四次挥手?

首先TCP是全双工的协议,那什么是全双工呢?下面是维基百科的解释:

全双工(full-duplex)的系统允许二台设备间同时进行双向数据传输。一般的电话、手机就是全双工的系统,因为在讲话时同时也可以听到对方的声音。全双工的系统可以用一般的双向车道形容。两个方向的车辆因使用不同的车道,因此不会互相影响。

接收到FIN时意味将没有数据再发来,但是还是可以继续发送数据

第一次挥手

主动发起断开的请求FIN,仅仅代表主动方不再发送数据报文,但是还是能接收数据报文

第二次挥手

被动方响应FIN,发送ACK,告知主动方知道你想断开了,这样主动方就不会一直发送断开的请求。

第三次挥手

被动方在处理完数据报文后,发送FIN给主动方,保证数据通信正常可靠。接着进入LAST_ACK(超时等待)阶段。

第四次挥手

主动方发送ACK响应报文,被动方释放链接。

为什么握手是3次,而挥手是4次?

当我们建立连接的时候,SYN和ACK是可以同事发送的。而关闭连接的时候FIN报文只能单独发送,因为客户端发送FIN报文时,服务端可能还在发送数据(全双工协议),所以没办法确定双方的数据传输完毕。只有当数据全部传输完毕了,才能关闭。