小结:TCP的十一种状态

860 阅读5分钟

TCP的十一种状态

本文正在参与 “网络协议必知必会”征文活动

由于TCP是双工的协议,并无实质上的客户端、服务端之分。我们在前面要先定义两个概念:主动请求方一般指客户端,被动等待端一般指服务端。方便概念理解。

共有状态

  1. CLOSED 状态 这种状态只是一种描述状态,描述的是TCP链接还未开始建立连接或者已经彻底释放的状态。在真实场景中对应的是双方互相不连接的状态。它的状态转换有两种:
  • 主动打开(Active Open) 主动访问请求(客户端请求)。
  • 被动打开(Passive Open) 等待客户端的新连接状态(服务端暴露端口等待访问)
  1. ESTABLISHED 状态 当接收到服务端传来的SYN+ACK值后,客户端会继续返回一个ACK值,如果服务端接收成功后,双方将都会进入ESTABLISHED状态,表示连接建立成功。

客户端专属状态

  1. SYN-SENT 状态 当客户端发送SYN报文后,等待服务端返回ACK的过程被称之为SYN-SENT状态。在此状态中当发送SYN后会同步启动一个定时器,如果超时后还未收到ACK会重发SYN。
  2. CLOSE-WAIT 状态 当服务端收到客户端FIN-WAIT-1状态下的FIN包,发送回复的ACK包后,进入CLOSE-WAIT状态。
  3. FIN-WAIT-1 状态 客户端尝试发送FIN包,等待服务端回复ACK时进入FIN-WAIT-1状态。(服务端也可以主动发送FIN包结束此次会话,此处只是为了方便叙述与理解)
  4. FIN-WAIT-2 状态 处于FIN-WAIT-1状态的连接收到ACK确认包以后进入FIN-WAIT-2状态,这个时候客户端的FIN包已经被对方确认,等待服务端发送FIN包,收到后,进入TIME-WAIT2 状态。
  5. TIME-WAIT 状态 收到被动关闭方的FIN包 后,发送确认ACK给客户端,开启2MSL定时器(一般为120S),定时器到期进入CLOSED状态,释放连接。

服务端专属状态

  1. LISTEN 状态 服务端调用bind、listen系统调用监听特定端口时进入到LISTEN状态,等待客户端发送SYN报文三次握手建立连接。
  2. SYN-RCVD 状态 服务端收到SYN报文会回复SYN+ACK,等待客户端ACK的时候进入SYN-RCVD状态。
  3. LAST-ACK 状态 当收到服务端的FIN包后,发送FIN包给服务端确认,等待客户端发送最后的ACK确认包时的状态。

特殊状态

CLOSING状态

同时关闭的情况,全双工协议下,当发起方发送FIN还未收到确认包的情况下。对方也发送了FIN请求断开连接时,将进入CLOSING状态,进入CLOSING状态后将会向对方发送ACK包来完成最后的CLOSED状态,最后完成关闭连接。

具体案例解析

只看上方的状态介绍是不是一头雾水,下面我们引入具体案例(TCP的三次握手与四次挥手)来具体讲解一下,各个状态在实际传输过程中的转换过程。

三次握手

初始的未连接状态我们称之为CLOSED 状态,表示服务端与客户端都处于待交互状态。
当客户端发送请求时,执行第一次握手确认

  • 客户端更新:SYN-SENT状态
  • 服务端更新:LISTEN状态 当服务端收到后,发送SYN_ACK包返回给客户端时,服务端处于等待回复状态,执行第二次握手确认
  • 服务端更新:SYN-RCVD状态 客户端回复ACK后,进入准备发送状态,等待服务端收到ACK后变化状态
  • 客户端在执行发送ACK操作后,更新为:ESTABLISHED状态,等待发送数据
  • 服务端在收到ACK后,也同样变更为 ESTABLISHED 状态,进入通信状态

此处介绍一下,由于TCP协议是双工协议,所以是支持双方同时发送给对方ACK进入第一次握手的。
当双方同时发送情况给对方时,执行第一次握手确认(暂时以a,b代指通信双方)

  • a 发送SYN包进入 SYN-SENT状态
  • b 发送SYN包后 同样进入 SYN-SENT状态 此时,如果a在等待b的回复(ACK+SYN)时收到了b的SYN包,会被动更新为 SYN-RCVD状态,回复b SYN+ACK包
  • a 收到b的SYN包后,回复b SYN+ACK包,更新为 SYN-RCVD状态
  • b 此时收到a的SYN+ACK包后,第二次握手成功,回复ACK包给a,完成最后一次握手

四次挥手

由于四次挥手是发生在断开连接的时候,所以客户端与服务端初始状态都为ESTABLISHED 状态。 客户端发送FIN包,请求断开,执行第一次挥手(发送FIN包后就不能再发送数据给服务端,但是可以继续接收服务端传来的数据,这种状态也被称为 半关闭状态)

  • 客户端在发送FIN包后, 更新为:FIN-WAIT1 状态 服务端在收到FIN包后,进行回复ACK包,如果有未发送完成的数据,也可以继续发送
  • 服务端更新为:CLOSE_WAIT 状态
  • 客户端在收到ACK包后,更新为:FIN-WAIT2 状态 服务端会继续发送FIN包给客户端
  • 服务端更新为:LAST-ACK 状态
  • 客户端更新为:TIME-WAIT 状态 客户端将会发送最后的ACK包,并等待两个MSL
  • 客户端更新为:CLOSED状态
  • 服务端在收到ACK后,关闭链接,更新为:CLOSED状态

到这里TCP的状态就结束了,个人理解,如果有错误或偏差,也希望大家多多指出斧正,感谢大家花时间读到这里。