TCP 首部

TCP 数据被封装在 IP 数据报中:

IP data

TCP 首部数据格式:

TCP header format

  • 每个 TCP 段都包含了源端口号目的端口号,用于寻找发端和接收端的应用程序。这两个端口号加上 IP 首部的源端 IP 地址目的端 IP 地址就可以确定一个TCP连接。
  • 序号:sequence number, 用来标识从 TCP 发端向 TCP 收端发送的数据字节流。
  • 确认序号:acknowledgement number, 确认序号只有在 ACK 标志位开启(值为1)时有效,值为要确认的数据包的 sequence number + 1。如客户端发送了一个数据包(序号为x)给服务端,则服务端收到这个数据包之后要回复一个确认数据包(确认序号x + 1)。
  • 标志位:共有 6 个,每个标志位用 1 和 0 分别表示开和关状态。

    • URG: The urgent point is valid. 当 URG=1 时,表示报文段中有紧急数据,应尽快传送。
    • ACK: The acknowledgement number is valid. 确认标志位,当 ACK=1 时,表示这是一个确认包。
    • PSH: The receiver should pass this data to the application as soon as possible. 当 PSH=1 时,接收端应尽快将数据交给应用程序。
    • RST: Reset the connection. 复位标志位,当 RST=1 时,表示 TCP 连接出现了严重错误,必须释放连接,重新建立连接。
    • SYN: Synchronize sequence numbers to initiate a connection. 在建立连接时,用来同步序号。SYN=1,ACK=0 表示发起请求连接;SYN=1,ACK=1 表示同意建立连接请求。
    • FIN: The sender is finished sending data.
  • 检验和:该字段检验的范围包括首部和数据,由发送端计算和存储,并由接收端进行检验。

  • 窗口:用来控制对方发送的数据量,通知发放已确定的发送窗口上限。
  • 紧急指针:在标志位 URG=1 时才有效,它指出本报文中的紧急数据的字节数。

每个TCP数据包的格式都是固定的,都包含了端口号,序号,确认序号,标志位等。

三次握手和四次握手

TCP 建立连接需要经过三次握手 (three-way handshake),关闭连接需要经过四次握手。

TCP three-way handshake

建立连接的三次握手

  • 第一次,客户端发送一个数据包:TCP首部的标志位SYN被设置为1,并且序号为初始序号ISN(Initial Sequence Number)。此时,客户端处于 SYN_SENT 状态。
  • 第二次,服务器收到客户端的连接请求后,由标志位SYN为1知道这个是建立TCP连接的请求,返回一个数据包:TCP首部的标志位SYN和ACK都被设置为1;序号为服务器端的ISN;确认序号为客户端序号 + 1。此时,服务器处于 SYN_RCVD 状态。
  • 第三次,客户端收到服务端的返回数据之后,由标志位SYN和ACK为1知道服务器同意建立TCP连接的确认数据包。检查确认序号的值(第一次握手客户端发送的序号 + 1),标志位SYN和ACK都正确之后,返回一个数据报给服务器:SYN=0;ACK=1;序号递增 (即上次序号 + 1);确认序号的值为服务器发送过来的序号 + 1。服务器收到这个数据包并检查数据报正确之后,客户端和服务端成功建立TCP连接,进入 ESTABLISHED 状态。

关闭连接的四次握手

  • 第一次,主动关闭的那一端(假设为客户端)发送一个关闭连接FIN数据包:TCP首部的标志位FIN设置为1;序号为正常递增值。此时,客户端进入为 FIN_WAIT_1 状态。
  • 第二次,另一端收到数据包之后,由FIN为1知道这是另一端关闭连接的请求。然后返回一个确认数据包:TCP首部标志位ACK设置为1;确认序号为发端序号 + 1;序号正常递增值。此时,服务器进入 CLOSE_WAIT 状态。当客户端收到确认数据包之后进入 FIN_WAIT_2 状态。
  • 第三次,当服务端发送完数据之后,向客户端发送一个关闭连接数据包:TCP首部的标志位FIN设置为1;序号为正常递增值。此时,服务端进入 LAST_ACK 状态。
  • 第四次,客户端收到数据包之后,由FIN为1知道这是服务端要关闭连接了,然后返回一个确认数据包:TCP首部标志位ACK设置为1;确认序号为收到的序号 + 1;序号为正常递增值。此时,客户端进入 TIME_WAIT 状态。

为什么建立连接是三次握手不是两次握手?关闭连接要四次握手?

  • 建立连接的时候,当客户端收到服务端的确认信息之后(第二次握手)就已经知道了服务端同意了连接,为什么还要再发送确认数据包给服务端(第三次握手)?

    第三次握手,是对第二次握手的确认。假如不进行第三次握手,服务端发送了SYN的确认数据包之后就直接处于 ESTABLISH 状态。这个确认数据包发送过程中出错,没有发送到给客户端怎么办?所以,一定要进行第三次握手。

  • 关闭TCP连接为什么要四次握手?

    TCP连接是全双工的通信,关闭的时候需要每个方向进行单独地关闭。当一端主动请求关闭的时候,被动的一端可能还有数据没有发送完毕,不能够立即关闭,所以不能够同时回复FIN + ACK,只能够先回复ACK数据包(第二次握手),此时属于半关闭状态。当处理完数据之后,被动关闭的一端再发送FIN包给主动关闭的一端关闭连接。

ISN

reference