在阐述TCP连接建立和终止的原理时,课本使用了Telnet的diacard服务。这里对Telnet作一个简短回顾。 Telnet协议允许用户通过网络登录远程的计算机系统。这里所指的计算机系统不仅仅是基于Unix的,只要支持Telnet协议的系统都可登录。登录通常需要账号,但有些远程主机允许无账号登录。连接一经建立,你在终端的任何按键都将传递给远程主机。Telnet服务的Well-known端口号是23。 telnet命令: telnet客户端有两种操作模式:输入模式(input mode)和命令模式(command mode)。不带参数直接执行telnet,终端显示“telnet>”提示符,这就是命令模式。在与服务器建立连接之后就进入输入模式。除了^],其他任何输入模式数据都将通过服务器telnet进程传输给服务器用作执行命令。”^]”是telnet的escape字符:从输入模式退出到命令模式(用Ctrl+]按键)。 几个telnet命令:
我们说发出第一个SYN的那端执行active open,而接收这个SYN,发出另一个SYN的那端执行passive open。 TCP连接终止 连接通常由客户端发起。但两端都可以主动关闭(active close)它,一般是由客户端来决定中止连接,因为它受用户交互。 在连接建立时可能超时,需要在若干时间后重试。 最大段大小(MSS)是TCP可以发送出去的最大数据块(chunk of data)。在连接建立时,每一端通告它的MSS。如果一端没有收到另一端的MSS通告,那么数据块大小将默认为536字节,IP数据报就是576字节(加20字节的IP头和20字节的TCP头)。 一般的,MSS越大越好,但要考虑分段(fragmentation)的因素。为避免分段,连接双方往往不发送超过较小MSS的数据块。但如果中间网络的MSS小于连接两端较小的MSS,比如两端MSS都是536,而中间网络的MSS是296,就将会发生分段,具体后续学习。 半关闭状态:连接一端停止了输出,但仍可以从另一端接收数据。
TCP状态迁移图
在ESTABLISHED状态,双方已经建立了连接,可以双向地进行数据传输。CLOSED实际上不是一个状态,这里假想它是状态的起点和终点。 如果状态SYN_RCVD是从LISTEN迁移过来的,那么它在收到RST(重置连接)后可以从SYN_RCVD返回到LISTEN;如果是从SYN_SENT迁移过来的,则不可再迁移到LISTEN状态。也就是说,我们执行被动打开(进入LISTEN状态),接收到一个SYN,并发送对它的ACK和另一个SYN,即进入SYN_RCVD状态。这时如果收到ACK,将进入ESTABLISHED状态;但要是收到RST,则又回到LISTEN状态,等待新的连接请求的到来。 TIME_WAIT状态也称为2MSL等待状态。在TCP实现中,必须给段最大生存时间(maximum segment lifetime ,MSL)指定一个值。这是TCP段在网络中存在而不被丢弃的最大时间量。但由于TCP段是封装在IP数据报中的,因此MSL又受TTL(IP数据报的存活时间)限制。在实际中TTL是基于跳(hop)的数目,而非计时器。 给MSL设置值的原则:TCP执行一个主动关闭,当它发送最后一个ACK后,连接必须在TIME_WAIT状态停留2倍MSL时间。这是为了在最后一个ACK丢失的情况下对其重发。处在TIME_WAIT状态的另一个影响是:在此连接中定义的socket对不能被重用,重用只能在2MSL状态结束以后。具体实例见课本P243-245。 当连接处于2MSL状态时,它的任何延迟的TCP段都将被丢弃。连接由socket对来定义,我们称一个连接的新的实例(instance)为该连接的一个化身(incarnation)。由于在2MSL状态时定义一个连接的socket对不能被重用,因此该连接前一个化身的TCP段是不会被后一个化身曲解(misinterprete)的。 通常是客户端执行主动关闭,进入TIME_WAIT状态,服务器执行被动关闭,不会进入TIME_WAIT状态。言下之意就是如果我们终止一个客户端,并立即重启一个相同客户端,那么新的客户端将不能使用相同的本地端口号。但这不成问题,因为客户端使用短暂的(ephemeral)端口,我们并不关心使用的本地端口号是多少。 但这对于服务器来说就不同了,因为服务器使用well-known端口号,比如telnet的23。如果我们终止一台已经建立连接的服务器,并立即重启,那么服务器将不能立即使用它的well-known端口号,因为这个端口号还是处在2MSL状态的连接的一部分。 考虑一种情况:主机有端口号处于2MSL状态,但它却在MSL时间内崩溃并重启,而且重启后使用崩溃前处于2MSL状态的端口号建立了新的连接,此时主机崩溃前连接的延迟TCP段就会被当前新的连接误用。为避免这种情况发生,RFC793规定在重启后的MSL时间内不应该建立新的连接,这称为quiet time。 一般来说,当一个到达的TCP段对于某个指定连接(referenced connection)不正确时,就需要发出一个重置段(reset segment)。 发出重置段的一个通常情况是:有连接请求到达,但却没有进程正在目标端口监听。比如telnet远程主机时指定一个不在使用的端口号,远程主机将发回一个重置段。看课本上列出的两个包: 0.0 bsdi.1087 > svr4.20000: S 297416193:297416193(0) win 4096 <mss 1024> [tos 0x10] 0.003771 (0.0038) svr4.20000 > bsdi.1087: R 0:0(0) ack 297416194 win 0 由于svr4收到的TCP段没有打开ACK,因此重置段的顺序号是0。尽管收到的TCP段不带实际数据,但由于SYN位在逻辑上占用了顺序号空间的一个字节,所以本例中重置段的应答号是ISN+数据长度(为0)+1,即297416194。 TCP连接的正常终止的情况:一端在所有排队数据发出后才发送一个FIN来终止连接,这也叫做有序释放(orderly release)。但有的时候可能用一个RST代替FIN来异常终止(abort)某个连接,有时也称之为异常释放(abortive release)。 异常释放带给了应用程序两个特征:1)任何在排队的数据都被丢弃(throw away),并立即发出重置段;2)重置段的接受者能够区分对方是异常,而非正常关闭。应用程序使用的API必须提供产生异常而非正常关闭的方法。示例见P247-248。
TCP连接的半打开(half-open)状态:一端已经关闭或者异常终止,却没有把这些通知给另一端。任何一端的主机崩溃(crash)都可能产生半打开状态。只要不打算在半打开的TCP连接上传输数据,仍处于连接状态的那一端就不会去检查另一端已经崩溃。 一种通常情况是连接的客户端掉电(power off),而服务器却不知道这个客户端已经消失。当客户端重启时将新建与服务器连接,这样就导致了服务器上很多的半打开TCP连接。 实践示例见P249。 两端的应用程序同时向对方执行主动打开的情况是可能的,尽管发生的概率很小,这称为同时打开(simultaneous open)。 TCP对同时打开进行了针对性的设计,遵守的原则是同时打开只建立一个连接,而非两个。 图:同时打开时的TCP段交换 同样地,连接两端同时执行主动关闭的情况称为同时关闭(simultaneous close)。同时关闭时TCP段交换的图见下: TCP选项和TCP服务器设计(略)。 |
|
来自: aquamarine > 《网络知识》