TCP 报文格式

其中重要字段:

  • 序号(sequence number):seq 序号,4 个字节。在一个 TCP 连接中传送的字节流的每一个字节都按顺序编号,seq 是本报文段的第一个字节的序号
  • 确认号(acknowledgement number):ack 序号,4 个字节。期望收到对方下一个报文段的第一个数据字节的序号,对方报文段最后一个字节序号加 1
  • 标志位(flags):0 或 1
    • 确认(ACK):ACK=1 时确认号才有效;
    • 同步(SYN):SYN=1 表示这是一个连接请求或连接接受报文
    • 终止(FIN):FIN 释放连接,FIN=1 表明数据发送完毕,要求释放运输连接

三次握手

  1. 客户端向服务器发送报文,标志位为 SYN,序号 seq=x,客户端进入 syn-sent 状态;
  2. 服务器收到并返回报文,标志位 SYN 和 ACK,序号 seq=y,确认号 ack=x+1,服务器进入 syn-rcvd 状态;
  3. 客户端收到并返回报文,标志位 ACK,序号 seq=x+1 即服务器的 ack,确认号 ack=y+1,客户端进入 established 状态,服务器收到报文后也进入 established 状态。

四次挥手

  1. 客户端向服务器发送报文,标志位 FIN,序号 seq=u,客户端进入 fin-wait-1 状态;
  2. 服务器收到报文进入 close-wait 状态并返回报文,标志位 ACK,序号 seq=y,确认号 ack=u+1;客户端收到报文进入 fin-wait-2 状态;
  3. 服务器做好了释放准备发送报文,标志位 FIN 和 ACK,序号 seq=w,确认号 ack=u+1,服务器进入 last-ack 状态;
  4. 客户端收到报文进入 time-wait 状态并返回报文,标志位 ACK,序号 seq=u+1,确认号 ack=w+1,客户端随后等待 2MSL;服务器收到报文进入 closed 状态,客户端等待完 2MSL 后进入 closed 状态

为什么是 3 次握手不是 2 次或 4 次?

2 次的问题:A 向 B 发送请求报文,B 收到回复 A 确认报文,但 B 无法确定 A 是否收到报文,A 也无法确定 B 是否收到请求报文(B 的确认报文可能丢失),造成死锁,;

4 次问题:A 向 B 发送请求报文,B 回复 A 确认报文,B 再向 A 发送请求报文,A 向 B 发送确认报文,其中 2、3 步可以合并提高连接速度

3 次握手中途请求失败怎么办?

  • 第一次发送 SYN 给服务器失败
    • 客户端会周期性重传,直到服务器收到
  • 第二次发送 SYN+ACK 失败
    • 服务器会周期性重传,直到客户端确认
  • 第三次发送 ACK 失败
    • 客户端单方面认为连接成功,此时:
      • a. 如果一直没有数据发送,服务器会周期性重传 SYN+ACK,直到客户端发送 ACK 成功(TCP 不会为没有数据的 ACK 超时重传)
      • b. 如果客户端有数据发送,服务器收到 data+ACK,自然会切换到连接状态,接受客户端的 data
      • c. 如果服务器有数据发送,数据发送不了(因为服务器状态还不是连接成功状态),服务器会周期性重传 SYN+ACK,直到客户端确认。

为什么 tcp 连接的时候是三次,断开的时候却是四次?

因为在连接的时候,服务器收到客户端的 SYN 请求时,可以直接发送 SYN+ACK,ACK 用来应答的,SYN 用来同步的;
但是在断开时,服务器收到客户端的 FIN 请求时,可能服务器还没向客户端发送完数据,只能先发送个 ACK,表示知道了,等服务器所有报文都发送完了,再向客户端发送 FIN+ACK,表示可以结束了

为什么客户端在结束后还要等 2MSL(最大报文段生存时间)才能到 closed 状态?

客户端需要判断最后的一个 ACK 服务器是否成功接收,2MSL 就是一个发送和一个回复所需的最大时间,如果最后的 ACK 丢失,服务器会向客户端继续发送 FIN+ACK 报文,客户端重发 ACK 并再次等待 2MSL,如果直到 2MSL,客户端都没有收到 FIN,客户顿则认为服务器已经收到 ACK,则结束 TCP 连接。

如果已经建立连接,客户端发生故障怎么办?

TCP 设有一个保活计时器,时间通常是 2 个小时,如果 2 小时内都没有收到客户端的任何数据,服务器会发送一个探测报文段,以后每隔 75s 发送一次,连发 10 次仍然没有回应,服务器认为客户端故障,则断开连接。

ISN 是什么?

initial sequence number,初始序列号。发送方的字节数据编号的原点

握手的第三次可以携带数据吗?

可以。能够发出第三次握手的用户应该是合法的用户,尽管服务器的状态还不是 established,但在收到第三次握手瞬间状态变为成功,数据可以成功接收。

ACK 标志位可以单独承担消息传递的任务吗?

不行!需要 ack number 配合,如果成功接收 ack number,则表明前面发送的数据已经被成功接收。