连接释放(四报文握手)

数据传输结束后,通信的双方都可释放连接。现在 A 和 B 都处于 ESTABLISHED 状态。

  1. A 的应用进程先向其 TCP 发出连接释放报文段,并停止再发送数据,主动关闭 TCP 连接。A 把连接释放报文段首部的终止控制位 FIN 置 1,其序号 seq=u,它等于前面已传送过的数据的最后一个字节的序号加 1。这时 A 进入 FIN-WAIT-1(终止等待 1)状态,等待 B 的确认。

  2. B 收到连接释放报文段后即发出确认,确认号是 ack=u+1,而这个报文段自己的序号是 v,等于 B 前面已传送过的数据的最后一个字节的序号加 1。然后 B 就进入 CLOSE-WAIT(关闭等待)状态

    这时从 A 到 B 这个方向的连接就释放了,这时的 TCP 连接处于半关闭 (half-close)状态,即 A 已经没有数据要发送了,但 B 若发送数据,A 仍要接收。

  3. A 收到来自 B 的确认后,就进入 FIN-WAIT-2(终止等待 2)状态,等待 B 发出的连接释放报文段。

  4. 若 B 已经没有要向 A 发送的数据,其应用进程就通知 TCP 释放连接。这时 B 发出的连接释放报文段必须使 FIN=1。现假定 B 的序号为 w(在半关闭状态中 B 可能又发送了一些数据)。B 还必须重复上次已发送过的确认号 ack=u+1。这时 B 就进入 LAST-ACK(最后确认)状态,等待 A 的确认。

  5. A 在收到 B 的连接释放报文段后,必须对此发出确认。在确认报文段中把 ACK 置 1,确认号 ack=w+1,而自己的序号是 seq=u+1 。然后进入到 TIME-WAIT(时间等待)状态

    现在 TCP 连接还没有释放掉。必须经过时间等待计时器(TIME-WAIT timer)设置的时间 2 MSL后,A 才进入到 CLOSED 状态。

    时间 MSL 叫做最长报文段寿命 (Maximum Segment Lifetime)。

  6. B 只要收到了 A 发出的确认,就进入 CLOSED 状态

为什么 A 在 TIME-WAIT 状态必须等待 2 MSL 的时间呢?

这有两个理由:

  • 第一,为了保证 A 发送的最后一个 ACK 报文段能够到达 B。这个 ACK 报文段有可能丢失,因而使处在 LAST-ACK 状态的 B 收不到对已发送的 FIN+ACK 报文段的确认

    • B 会超时重传这个 FIN+ACK 报文段,而 A 就能在 2 MSL 时间内收到这个重传的 FIN+ACK 报文段。

    • 接着 A 重传一次确认,重新启动 2 MSL 计时器。最后,A 和 B 都正常进入到 CLOSED 状态。

    如果 A 在 TIME-WAIT 状态不等待一段时间,而是在发送完 ACK 报文段后立即释放连接,那么就无法收到 B 重传的 FIN+ACK 报文段,因而也不会再发送一次确认报文段。这样,B 就无法按照正常步骤进入 CLOSED 状态。

  • 第二,防止“已失效的连接请求报文段”出现在本连接中。A 在发送完最后一个 ACK 报文段后,再经过时间 2 MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。

保活计时器 (keepalive timer)

除时间等待计时器外,TCP 还设有一个保活计时器 (keepalive timer)。设想有这样的情况:客户已主动与服务器建立了 TCP 连接。但后来客户端的主机突然出故障。显然,服务器以后就不能再收到客户发来的数据。因此,应当有措施使服务器不要再白白等待下去。这就是使用保活计时器。

服务器每收到一次客户的数据,就重新设置保活计时器,时间的设置通常是两小时。若两小时没有收到客户的数据,服务器就发送一个探测报文段,以后则每隔 75 秒钟发送一次。若一连发送 10 个探测报文段后仍无客户的响应,服务器就认为客户端出了故障,接着就关闭这个连接。

Last updated