收到本方应用进程的关闭命令后, TCP 在发送完还没有处理的报文段后,发 FIN = 1 的报文段给对方,且 TCP 再也不受理本方应用进程的数据发送。在 FIN 之前发送的数据字节,包括 FIN ,都须要对方确认,不然要重传。注意 FIN 也占一个顺序号。一旦收到对方对 FIN 的确认以及对方的 FIN 报文段,本方 TCP 就对该 FIN 进行确认,在等待一段时间,而后关闭链接。等待是为了防止本方的确认报文丢失,避免对方的重传报文干扰新的链接。
当 TCP 收到对方发来的 FIN 报文时,发 ACK 确认此 FIN 报文,并通知应用进程链接正在关闭。应用进程将以关闭命令响 应。 TCP 在发送完还没有处理的报文段后,发一个 FIN 报文给对方 TCP ,而后等待对方对 FIN 的确认,收到确认后关闭链接。若对方的确认未及时到达,在等待一段时间后也关闭链接。
链接双方的应用进程同时发关闭命令,则双方 TCP 在发送完还没有处理的报文段后,发送 FIN 报文。各方 TCP 在 FIN 前所发报文都获得确认后,发 ACK 确认它收到的 FIN 。各方在收到对方对 FIN 的确认后,一样等待一段时间再关闭链接。这称之为同时关闭( simultaneous close )。www.2cto.com
TCP 协议的操做可使用一个具备 11 种状态的有限状态机( Finite State Machine )来表示,图 3-12 描述了 TCP 的有限状态机,图中的圆角矩形表示状态,箭头表示状态之间的转换,各状态的描述如表 3-2 所示。图中用粗线表示客户端主动和被动的服务器端创建链接的正常过程:客户端的状态变迁用粗实线,服务器端的状态变迁用粗虚线。细线用于不常见的序列,如复位、同时打开、同时关闭等。图中的每条状态变换线上均标有“事件/动做”:事件是指用户执行了系统调用( CONNECT 、 LISTEN 、 SEND 或 CLOSE )、收到一个报文段( SYN 、 FIN 、 ACK 或 RST )、或者是出现了超过两倍最大的分组生命期的状况;动做是指发送一个报文段( SYN 、 FIN 或 ACK )或什么也没有(用“-”表示)。
图 3-12 TCP 有限状态机。粗实线表示客户的正常路径;
粗虚线表示服务器的正常路径;细线表示不常见的事件。
每一个链接均开始于 CLOSED 状态。当一方执行了被动的链接原语( LISTEN )或主动的链接原语( CONNECT )时,它便会脱离 CLOSED 状态。若是此时另外一方执行了相对应的链接原语,链接便创建了,而且状态变为 ESTABLISHED 。任何一方都可以首先请求释放链接,当链接被释放后,状态又回到了 CLOSED 。
表 3-2 TCP 状态表
1. 正常状态转换
咱们用图 3-13 来显示在正常的 TCP 链接的创建与终止过程当中,客户与服务器所经历的不一样状态。读者能够对照图 3-12 来
阅读,使用图 3-12 的状态图来跟踪图 3-13 的状态变化过程,以便明白每一个状态的变化:
服务器端首先执行 LISTEN 原语进入被动打开状态( LISTEN ),等待客户端链接;www.2cto.com
当客户端的一个应用程序发出 CONNECT 命令后,本地的 TCP 实体为其建立一个链接记录并标记为 SYN SENT 状态,而后给服务器发送一个 SYN 报文段;
服务器收到一个 SYN 报文段,其 TCP 实体给客户端发送确认 ACK 报文段同时发送一个 SYN 信号,进入 SYN RCVD 状态;
客户端收到 SYN + ACK 报文段,其 TCP 实体给服务器端发送出三次握手的最后一个 ACK 报文段,并转换为 ESTABLISHED 状态;
服务器端收到确认的 ACK 报文段,完成了三次握手,因而也进入 ESTABLISHED 状态。
在此状态下,双方能够自由传输数据。当一个应用程序完成数据传输任务后,它须要关闭 TCP 链接。假设仍由客户端发起主动关闭链接。
客户端执行 CLOSE 原语,本地的 TCP 实体发送一个 FIN 报文段并等待响应的确认(进入状态 FIN WAIT 1 );
服务器收到一个 FIN 报文段,它确认客户端的请求发回一个 ACK 报文段,进入 CLOSE WAIT 状态;
客户端收到确认 ACK 报文段,就转移到 FIN WAIT 2 状态,此时链接在一个方向上就断开了;
服务器端应用获得通告后,也执行 CLOSE 原语关闭另外一个方向的链接,其本地 TCP 实体向客户端发送一个 FIN 报文段,并进入 LAST ACK 状态,等待最后一个 ACK 确认报文段;www.2cto.com
客户端收到 FIN 报文段并确认,进入 TIMED WAIT 状态,此时双方链接均已经断开,但 TCP 要等待一个 2 倍报文段最大生存时间 MSL ( Maximum Segment Lifetime ),确保该链接的全部分组所有消失,以防止出现确认丢失的状况。当定时器超时后, TCP 删除该链接记录,返回到初始状态( CLOSED )。
服务器收到最后一个确认 ACK 报文段,其 TCP 实体便释放该链接,并删除链接记录,返回到初始状态( CLOSED )。
2. 同时打开:
尽管发生的可能性极小,两个应用程序同时彼此执行主动打开的状况仍是可能的。每一方必须发送一个 SYN ,且这些 SYN 必须传递给对方。这须要每一方使用一个对方周知的端口做为本地端口。例如,主机 A 中的一个应用程序使用本地端口 7777 ,并与主机 B 的端口 8888 执行主动打开。主机 B 中的应用程序则使用本地端口 8888 ,并与主机 A 的端口 7777 执行主动打开。 TCP 是特地设计为了能够处理同时打开,对于同时打开它仅创建一条链接而不是两条链接(其余的协议族,最突出的是 OSI 传输层,在这种状况下将创建两条链接而不是一条链接)。www.2cto.com
当出现同时打开的状况时,状态变迁与图 3-13 所示的不一样。两端几乎在同时发送 SYN ,并进入 SYN_SENT 状态。当每一端收到 SYN 时,状态变为 SYN_RCVD ,同时它们都再发 SYN 并对收到的 SYN 进行确认。当双方都收到 SYN 及相应的 ACK 时,状态都变迁为 ESTABLISHED 。图 3-14 显示了这些状态变迁过程。
图 3-14 同时打开期间报文段的交换
一个同时打开的链接须要交换 4 个报文段,比正常的三次握手多一个。此外,要注意的是咱们没有将任何一端称为客户或服务器,由于每一端既是客户又是服务器。
3. 同时关闭:
正常状况下都是由一方(一般但不老是客户方)发送第一个 FIN 执行主动关闭,但双方都执行主动关闭也是可能的, TCP 协议也容许这样的同时关闭。www.2cto.com
在图 3-12 中,当两端应用层同时发出关闭命令时,两端均从 ESTABLISHED 变为 FIN_WAIT_1 。这将致使双方各发送一个 FIN ,两个 FIN 通过网络传送后分别到达另外一端。收到 FIN 后,状态由 FIN_WAIT_1 变迁到 CLOSING ,并发送最后的 ACK 。当收到最后的 ACK 时,状态变化为 TIME_WAIT 。图 3-15 总结了这些状态的变化,从图中能够看出同时关闭与正常关闭使用的报文段交换数目相同。
图 3-15 同时关闭期间的报文段交换
4. 其它状况:
服务方打开:从 LISTEN 到 SYN_SENT 的变迁是正确的,它由服务器端主动发出 SYN 报文段,但 Berkeley 版的 TCP 软件并不支持它。
重置链接(复位):只有当 SYN_RCVD 状态是从 LISTEN 状态(正常状况)进入,而不是从 SYN_SENT 状态(同时打开)进入时,从 SYN_RCVD 回到 LISTEN 的状态变迁才是有效的。这意味着若是咱们执行被动打开(进入 LISTEN ),收到一个 SYN ,发送一个带 ACK 的 SYN (进入 SYN_RCVD ),而后收到一个 RST ,而不是一个 ACK ,便又回到 LISTEN 状态并等待另外一个链接请求的到来。www.2cto.com
快速关闭:在主动关闭后的 FIN_WAIT_1 状态,若是收到的报文段不只是 ACK ,并且还包括对方的 FIN 信号,则直接进入 TIME_WAIT 状态,给对方发送 ACK 报文段,而后等待超时。
另外, TIME_WAIT 状态的等待超时须要再详细解释一下,由于它直接影响到网络应用程序的表现。
每一个具体 TCP 实现必须选择一个报文段最大生存时间 MSL ( Maximum Segment Lifetime ),它是任何报文段被丢弃前在网络内的最长时间。咱们知道这个时间是有限的,由于 TCP 报文段以 IP 数据报在网络内传输,而 IP 数据报有限制其生存时间的 TTL 字段。 RFC 793 [Postel 1981c ] 指出 MSL 为 2 分钟。然而,实现中的经常使用值是 30 秒、 1 分钟、或 2 分钟。
对一个具体实现所给定的 MSL 值,处理的原则是:当 TCP 执行一个主动关闭,并发回最后一个 ACK ,该链接必须在 TIME_WAIT 状态停留的时间为 2 倍的 MSL ,所以 TIME_WAIT 状态也称为 2MSL 等待状态。在这段时间内,若是最后的 ACK 丢失,对方会超时并重发最后的 FIN ,这样本地 TCP 能够再次发送 ACK 报文段(这也是它惟一能够发送的报文,并重置 2MSL 定时器)。
这种 2MSL 等待的另外一个结果是这个 TCP 链接在 2MSL 等待期间,定义这个链接的套接字( socket ,客户的 IP 地址和端口号,服务器的 IP 地址和端口号)不能再被使用。这个链接只能在 2MSL 结束后才能再被使用。在链接处于 2MSL 等待时,任何迟到的报文段将被丢弃。www.2cto.com
咱们假设图 3-12 中是客户执行主动关闭并进入 TIME_WAIT ,这是正常的状况,由于服务器一般执行被动关闭,不会进入 TIME_WAIT 状态。这暗示若是咱们终止一个客户程序,并当即从新启动这个客户程序,则这个新客户程序将不能重用相同的本地端口。这不会带来什么问题,由于客户使用本地端口,而并不关心这个端口号是什么。然而,对于服务器,状况就有所不一样,由于服务器使用周知端口。 若是咱们终止一个已经创建链接的服务器程序,并试图当即从新启动这个服务器程序,服务器程序将不能把它的这个周知端口赋值给它的端点,由于那个端口是处于 2MSL 链接的一部分。在从新启动服务器程序前,它须要在 1~4 分钟。这就是不少网络服务器程序被杀死后不可以立刻从新启动的缘由(错误提示为“ Address already in use ”)。