相较于全双工的双向同时传输,半双工则比较弱,它不支持双向同时传输,同一时刻只能传输一个方向的数据。如下图所示,当 A 向 B 发送数据时,B 不能向 A 发送数据。同样的,当 B 向 A 发送数据时,A 也不能向 B 发送数据。可见,半双工的一个连接只能分时使用。
全双工支持两个方向的数据同时传输,可以从逻辑上将其理解为由两个半双工的连接构成。如下图所示,一个逻辑连接用于支持 A 向 B 发送数据,另一个逻辑连接用于支持 B 向 A 发送数据,两者之间互不影响。
在了解了全双工的概念后,我们来看下 TCP 连接建立与终止过程。
TCP在建立连接时,通常需要三次握手。以「TCP/IP 详解 卷1:协议」第 18 章建立连接的示例为例,来看下 TCP 连接的建立过程。
sv44.1037
与 bsdi.discard
是网络上的两个主机,bsdi.discard
是一个服务器,sv44.1037
主动发起请求并建立 TCP 连接。如下图所示,它们之间共发送了三个报文段来建立连接。
其中,每个报文段的内容含义如下:
报文段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
,报文中的数据字节数为 0
。ack 1415531522
表示确认序号,也就是期望收到的下一个分组的开始序号。
报文段 3
请求端对服务器发送的 ISN 加 1,作为 ACK 回复服务器,以对服务器发送的 ISN 进行确认。在这之后,TCP 连接就完成了建立过程。
这三个报文段用于完成 TCP 连接的建立,连接建立的过程也叫做三次握手(three-way handshake)。
发送第一个 SYN 的一端执行主动打开(active open),接收这个 SYN 并发回下一个 SYN 的另一端执行被动打开(passive open)。此外还存在一种情况,即双方同时发送 SYN 进而都执行主动打开。
终止一个 TCP 连接需要四次挥手。
sv44.1037
主动发起的终止连接请求,双方共发送了四个报文段。
报文段 1
sv44.1037
发送了 FIN 报文段,表示要关闭这个方向(从 sv44.1037
到 bsdi.discard
)上的连接。
报文段 2
bsdi.discard
对报文段 1 进行了确认,这之后就关闭了一个方向(从 sv44.1037
到 bsdi.discard
)的连接
报文段 3
bsdi.discard
发送了 FIN 报文段,表示关闭另一个方向(从 bsdi.discard
到 sv44.1037
)上的连接。因为前一个方向的连接已关闭,所以该报文段的 ACK 不变。
报文段 4
sv44.1037
对报文段 3 进行确认,之后就关闭了 TCP 连接。
TCP 是全双工的,所以每个方向的连接都需要单独建立和终止。
在建立 TCP 连接时,报文段 1 表示请求建立一个方向的连接,报文段 2 对报文段 1 进行确认,完成该方向的连接建立。同时,报文段 2 还会带上另一个方向的建立连接请求。最终,报文段 3 对报文段 2 的建立连接请求进行确认,进而完成 TCP 连接的建立。
在发送完报文段 2 之后,服务端的 TCP 连接会进入半连接状态。在这之后,接收到报文段 3 时,它的 TCP 状态会变为全连接状态。
在终止 TCP 连接时,报文段 1 和 报文段 2 完成一个方向的连接终止。此时,服务端的数据可能还未发送完,它还可以继续发送数据。客户端则只能接收数据,同时等待另一个方向的终止请求。当收到服务端的终止请求报文段 3 时,客户端回复确认报文段,完成 TCP 连接的终止。
建立连接时,至少需要三个报文段,才能完成双向连接的确认,其中被动方在发送 SYN 的同时对另一方的 SYN 进行确认。
断开连接时,因为要处理半关闭状态,还可以单向继续发送数据,所以被动方是先对另一方的 FIN 进行确认,待自己的数据发送完之后再发送 FIN,这样最终就需要四个报文段。
TCP/IP 详解 卷1:协议