TCP协议

特点

  • 面向连接: 通信双方必须先建立连接,为连接分配内核资源,管理连接的状态和连接上数据的传输。完成数据交换后必须断开连接
  • 字节流: 发送端执行的写操作次数和接收端执行的读操作次数没有任何数据关系
  • 可靠传输: 发送应答、超时重发、接收端会对报文进行重排和整理

TCP头部结构

TCP header

  • 16位端口号(port number)
  • 32位序号(sequence number): 一次TCP通信过程中某一个传输方向上的字节流的每个字节的编号,由初始序号(initial sequence number)开始累加,序号值为第一个字节在整个字节流中的偏移
  • 32位确认号(acknowledgement number): 对另一方TCP报文的响应,对方序号值加1
  • 4位头部长度(header length): 32bit字(4字节)的数目,4位最大表示15,TCP头部最长60字节
  • 6位标志位
    • URG(urgent): 紧急指针是否有效
    • ACK(acknowledgement): 确认号是否有效,携带ACK标志的报文为确认报文
    • PSH(push): 提示接收端立即从TCP缓冲区中读走数据,为接收后续数据腾出空间
    • RST(reset): 要求对方重新建立连接,携带RST标志的报文为复位报文
    • SYN(synchronous): 要求建立连接,携带SYN标志的报文为同步报文
    • FIN(finish): 通知对方本端要关闭连接了,携带FIN标志的报文为结束报文
  • 16位窗口大小(window size): 流量控制的手段,告诉对方本端的接收缓冲区还能容纳多少字节的数据,对方可以控制发送速度
  • 16位校验和(checksum): 接收端使用CRC算法检验TCP报文是否损坏,校验包括头部和数据
  • 16位紧急指针(urgent pointer): 正的偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号
  • 选项字段(option): 可变长的可选信息

TCP连接的建立

TCP connection establishment

连接建立的过程称为三次握手(three-way handshake)

  1. 客户端发送一个包含初始序号(ISN)的SYN报文,表明客户端打算连接服务器的端口
  2. 服务器发回包含服务器初始序号(ISN)的SYN报文作为应答,同时,将确认序号设置为客户端的ISN加1以对客户端的SYN报文进行确认
  3. 客户端将确认序号置为服务器的ISN加1以对服务器的SYN报文进行确认

ISN可以看作是一个32比特的计数器,随时间而变化,每4ms加1,每个连接都有不同的ISN

TCP连接的终止

TCP connection termination

终止连接需要4次握手,由于TCP是全双工的,因此每个方向都可以单独地进行关闭。

首先进行关闭的一方将执行主动关闭,另一方执行被动关闭

  1. 主动关闭方会发送一个FIN给被动关闭方,表示数据已经发送完毕
  2. 被动关闭方接收到FIN,响应一个ACK。它的接收作为一个文件结束符(end-of-file)传递给接收端应用进程(放在所有已排队等候该应用进程接收的任何其他数据之后)。FIN意味着接收端在相应连接上再无额外的数据可以接收了
  3. 一段时间后,被动关闭方的应用进程收到了文件结束符,发送完所有需要发送的内容,也会发送一个FIN给主动关闭方
  4. 接收到这个最终的FIN的主动关闭方也需要响应一个ACK

TCP状态变迁

TCP state transition

服务器建立连接状态转移

  1. 服务器通过listen调用进入LISTEN状态,被动等待客户端连接
  2. 服务器监听到某个连接请求(SYN报文),就将该连接放入内核等待队列中,并向客户端发送SYN+ACK报文,此时处于SYN_RCVD状态
  3. 如果服务器成功接收到客户端发送的ACK报文,则连接转移到ESTABLISHED状态

服务器关闭连接状态转移

  1. 客户端主动关闭连接(通过close、shutdown系统调用向服务器发送FIN报文),服务器通过返回ACK报文使连接进入CLOSE_WAIT状态
  2. 服务器立即向客户端发送结束报文来关闭连接,状态转移到LAST_ACK,等待客户端对结束报文的最后一次确认

客户端建立连接状态转移

  1. 客户端通过connect系统调用主动与服务器建立连接,发送一个SYN报文,状态转移到SYN_SENT
  2. 可能有两个原因导致失败,调用失败立即返回初始的CLOSED状态
    • 目标端口不存在,或者任处于TIME_WAIT状态的连接所占用,服务器给客户端发送一个复位报文,connect调用失败
    • 目标端口存在,但是超时未收到确认报文,则connect调用失败
  3. 客户端接收到服务器的ACK+SYN报文,发送ACK报文,connect调用成功,状态转移到ESTABLISHED状态

客户端关闭连接状态转移

  1. 客户端向服务器发送一个FIN报文,进入FIN_WAIT_1状态
  2. 收到服务器发送的ACK报文,进入FIN_WAIT_2状态。此时服务器处于CLOSE_WAIT状态,这一对状态可能发生半关闭的状态
  3. 收到服务器发送的FIN报文,返回ACK报文,进入TIME_WAIT状态
  4. 如果收到服务器发送的ACK+FIN报文,则不经过FIN_WAIT_2,直接进入TIME_WAIT状态

11种状态

  • CLOSED: 假想的状态起始点
  • LISTEN: 等待客户端连接请求,服务器经过 socket()、bind()、listen() 之后进入此状态
  • SYN_SENT: 客户端发起连接,调用connect(),发送SYN给服务器,等待匹配的ACK,如果服务器不能连接,则进入CLOSED
  • SYN_RCVD: 服务器接收到客户端的SYN,同时返回一个SYN+ACK,等待客户端的ACK
  • ESTABLISHED: 客户端收到服务器的SYN+ACK,同时返回一个ACK,客户端进入ESTABLISHED,服务器收到ACK后进入ESTABLISHED
  • FIN_WAIT_1: 主动关闭的一方调用close(),发送FIN给对方,等待对方返回ACK
  • FIN_WAIT_2: 主动关闭的一方收到对方的ACK
  • CLOSING: 两边同时发送FIN,主动关闭方由FIN_WAIT_1直接进入此状态
  • CLOSE_WAIT: 被动关闭的一方接收到对方的FIN,并返回一个ACK,等待上层调用close()
  • LAST_ACK: 被动关闭方发送FIN,等待对方返回ACK
  • TIME_WAIT: 等待足够的时间确保迟到的报文消失

TCP state transition flow

TIME_WAIT状态

主动关闭方响应完最后一次ACK之后,会在TIME_WAIT这个状态维持2MSL的时间

MSL(maximum segment lifetime),报文最大生存时间。MSL是任何IP数据报能够在因特网存活的最长时间,RFC1122建议值是2min

  • 可靠地终止TCP连接: 如果服务器没有收到确认FIN的ACK,可能会重新发送FIN,此时客户端需要重新发送ACK报文
  • 保证让迟来的TCP报文有足够的时间被识别并丢弃: 如果没有TIME_WAIT,应用程序能够建立一个和刚关闭的连接相似的连接(相同IP和端口),这个新连接可能会收到属于原来连接的TCP报文
  • 确保网络上两个传输方向上尚未被接收到的、迟到的TCP报文消失

服务端主动关闭连接的TIME_WAIT?