TCP的三次握手与四次挥手

TCP 是一个面向连接的协议,它是全双工的,允许在两个方向上同时传输数据。建立一个 TCP 连接通常需要三次握手,也就是说连接的双方共需要发送三个报文段。而终止一个连接则需要经过四次握手,即发送四个报文段。

全双工与半双工

在开始之前先了解下全双工与半双工的区别。

对于一个已建立的连接,全双工支持在两个方向同时传输数据。如下图所示,在同一时刻,A 可以向 B 发送数据,B 也可以向 A 发送数据。

全双工 Full DuplexAABB这是一个连接A 可以向 B 发送数据B 也可以同时向 A 发送数据

相较于全双工的双向同时传输,半双工则比较弱,它不支持双向同时传输,同一时刻只能传输一个方向的数据。如下图所示,当 A 向 B 发送数据时,B 不能向 A 发送数据。同样的,当 B 向 A 发送数据时,A 也不能向 B 发送数据。可见,半双工的一个连接只能分时使用。

半双工 Half DuplexAABBA 发送数据这是一个连接A 向 B 发送数据B 发送数据还是上面那个连接B 向 A 发送数据

如何理解全双工

全双工支持两个方向的数据同时传输,可以从逻辑上将其理解为由两个半双工的连接构成。如下图所示,一个逻辑连接用于支持 A 向 B 发送数据,另一个逻辑连接用于支持 B 向 A 发送数据,两者之间互不影响。

全双工的理解AABBalt[逻辑上的理解]逻辑上 A 到 B 的连接A 向 B 发送数据逻辑上 B 到 A 的连接同时 B 也可以向 A 发送数据

TCP 连接的建立与终止

在了解了全双工的概念后,我们来看下 TCP 连接建立与终止过程。

TCP 连接的建立

TCP在建立连接时,通常需要三次握手。以「TCP/IP 详解 卷1:协议」第 18 章建立连接的示例为例,来看下 TCP 连接的建立过程。

sv44.1037bsdi.discard 是网络上的两个主机,bsdi.discard 是一个服务器,sv44.1037 主动发起请求并建立 TCP 连接。如下图所示,它们之间共发送了三个报文段来建立连接。

TCP 的三次握手svr4.1037svr4.1037bsdi.discardbsdi.discardSYN 1415531521:1415531421(0)<mss 1024>报文段 1SYN 1823083521:1823083521(0)ack 1415531522, <mss 1024>报文段 2ack 1823083522报文段 3

其中,每个报文段的内容含义如下:

  • 报文段1

    请求端发送一个 SYN 报文段,指明打算连接的服务器的端口、初始序号 ISN。

    1415531521:1415531421(0) 表示 svr4.1037 发送的分组序号是 1415531521 ,报文中的数据字节数为 0<mss 1024> 表示发送端指明的最大报文段长度,发送端将不接收超过这个长度的 TCP 报文段。

  • 报文段2

    服务器发回包含自己 ISN 的 SYN 报文段作为应答,同时要发送 ACK 对请求方的 ISN 进行确认。因为一个 SYN 会占用一个序号,所以 ACK 中的序号为请求方的 ISN + 1。

    1823083521:1823083521(0) 表示 bsdi.discard 发送的分组序号是 1823083521,报文中的数据字节数为 0ack 1415531522 表示确认序号,也就是期望收到的下一个分组的开始序号。

  • 报文段 3

    请求端对服务器发送的 ISN 加 1,作为 ACK 回复服务器,以对服务器发送的 ISN 进行确认。在这之后,TCP 连接就完成了建立过程。

这三个报文段用于完成 TCP 连接的建立,连接建立的过程也叫做三次握手(three-way handshake)。

发送第一个 SYN 的一端执行主动打开(active open),接收这个 SYN 并发回下一个 SYN 的另一端执行被动打开(passive open)。此外还存在一种情况,即双方同时发送 SYN 进而都执行主动打开。

TCP 连接的终止

终止一个 TCP 连接需要四次挥手。

sv44.1037 主动发起的终止连接请求,双方共发送了四个报文段。

TCP的四次挥手svr4.1037svr4.1037bsdi.discardbsdi.discardFIN 1415531522:1415531422(0) ack 1823083522报文段 1ack 1415531523报文段 2FIN 1823083522:1823083522(0) ack 1415531523报文段 3ack 1823083523报文段 4
  • 报文段 1

    sv44.1037 发送了 FIN 报文段,表示要关闭这个方向(从 sv44.1037bsdi.discard )上的连接。

  • 报文段 2

    bsdi.discard 对报文段 1 进行了确认,这之后就关闭了一个方向(从 sv44.1037bsdi.discard )的连接

  • 报文段 3

    bsdi.discard 发送了 FIN 报文段,表示关闭另一个方向(从 bsdi.discardsv44.1037 )上的连接。因为前一个方向的连接已关闭,所以该报文段的 ACK 不变。

  • 报文段 4

    sv44.1037 对报文段 3 进行确认,之后就关闭了 TCP 连接。

为何需要三次握手与四次挥手

TCP 是全双工的,所以每个方向的连接都需要单独建立和终止。

TCP的三次握手与四次挥手客户端客户端服务端服务端三次握手SYN报文段 1SYN + ack报文段 2ack报文段 3四次挥手FIN报文段 4FIN 的 ack报文段 5FIN报文段 6FIN 的 ack报文段 7

三次握手

在建立 TCP 连接时,报文段 1 表示请求建立一个方向的连接,报文段 2 对报文段 1 进行确认,完成该方向的连接建立。同时,报文段 2 还会带上另一个方向的建立连接请求。最终,报文段 3 对报文段 2 的建立连接请求进行确认,进而完成 TCP 连接的建立。

在发送完报文段 2 之后,服务端的 TCP 连接会进入半连接状态。在这之后,接收到报文段 3 时,它的 TCP 状态会变为全连接状态。

四次挥手

在终止 TCP 连接时,报文段 1 和 报文段 2 完成一个方向的连接终止。此时,服务端的数据可能还未发送完,它还可以继续发送数据。客户端则只能接收数据,同时等待另一个方向的终止请求。当收到服务端的终止请求报文段 3 时,客户端回复确认报文段,完成 TCP 连接的终止。

总结

建立连接时,至少需要三个报文段,才能完成双向连接的确认,其中被动方在发送 SYN 的同时对另一方的 SYN 进行确认。

断开连接时,因为要处理半关闭状态,还可以单向继续发送数据,所以被动方是先对另一方的 FIN 进行确认,待自己的数据发送完之后再发送 FIN,这样最终就需要四个报文段。

参考

TCP/IP 详解 卷1:协议