TCP 状态详解 -转载

TCP 是一个面向链接的协议,不管哪一方向另外一方发送数据以前,都必须先在双方之间创建一条链接。本节将详细讨论一个TCP 链接是如何创建的以及通讯结束后是如何终止的。服务器

创建一个 TCP 链接
  TCP使用三次握手 ( three-way handshake ) 协议来创建链接,图 3-10 描述了三次握手的报文序列。
www.2cto.com

这三次握手为:
请求端(一般称为客户)发送一个 SYN 报文段( SYN 为 1 )指明客户打算链接的服务器的端口,以及初始顺序号( ISN )。
服务器发回包含服务器的初始顺序号的 SYN 报文段( SYN 为 1 )做为应答。同时,将确认号设置为客户的 ISN 加 1 以对客户的 SYN 报文段进行确认( ACK 也为 1 )。
客户必须将确认号设置为服务器的 ISN 加 1 以对服务器的 SYN 报文段进行确认( ACK 为 1 ),该报文通知目的主机双方已完成链接创建。
 
发送第一个 SYN 的一端将执行主动打开( active open ),接收这个 SYN 并发回下一个 SYN 的另外一端执行被动打开( passive open )。另外, TCP 的握手协议被精心设计为能够处理同时打开( simultaneous open ),对于同时打开它仅创建一条链接而不是两条链接。所以,链接能够由任一方或双方发起,一旦链接创建,数据就能够双向对等地流动,而没有所谓的主从关系。
www.2cto.com
 
  三次握手协议是链接两端正确同步的充要条件。由于 TCP 创建在不可靠的分组传输服务之上,报文可能丢失、延迟、重复和乱序,所以协议必须使用超时和重传机制。若是重传的链接请求和原先的链接请求在链接正在创建时到达,或者当一个链接已经创建、使用和结束以后,某个延迟的链接请求才到达,就会出现问题。采用三次握手协议(加上这样的规则:在链接创建以后 TCP 就再也不理睬又一次的链接请求)就能够解决这些问题。
 
  三次握手协议能够完成两个重要功能:它确保链接双方作好传输准备,并使双方统一了初始顺序号。初始顺序号是在握手期间传输顺序号并得到确认:当一端为创建链接而发送它的 SYN 时,它为链接选择一个初始顺序号;每一个报文段都包括了顺序号字段和确认号字段,这使得两台机器仅仅使用三个握手报文就能协商好各自的数据流的顺序号。通常来讲, ISN 随时间而变化,所以每一个链接都将具备不一样的 ISN 。www.2cto.com
 
关闭一个 TCP 链接
  TCP 链接创建起来后,就能够在两个方向传送数据流。当 TCP 的应用进程再没有数据须要发送时,就发关闭命令。 TCP 经过发送控制位 FIN=1 的数据片来关闭本方数据流,但还能够继续接收数据,直到对方关闭那个方向的数据流,链接就关闭。
 
  TCP 协议使用修改的三次握手协议来关闭链接, 如图 3-11 所示,即终止一个链接要通过 4 次握手。这是由于 TCP 的半关闭( half-close )形成的。因为一个 TCP 链接是全双工(即数据在两个方向上能同时传递),所以每一个方向必须单独地进行关闭。关闭的原则就是当一方完成它的数据发送任务后就能发送一个 FIN 来终止这个方向链接。当一端收到一个 FIN ,它必须通知应用层另外一端已经终止了那个方向的数据传送。发送 FIN 一般是应用层进行关闭的结果。
 
从一方的 TCP 来讲,链接的关闭有三种状况:www.2cto.com   、
• 本方启动关闭
  收到本方应用进程的关闭命令后, 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 状态机
  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 ”)。
相关文章
相关标签/搜索