目录
3.5 为什么客户端在TIME-WAIT状态必须等待2MSL的时间呢?
从通信和信息处理的角度看,传输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。当网络的边缘部分中的两台主机使用网络的核心部分的功能进行端到端的通信时,只有主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时都只用到下三层的功能。
如下图,假设局域网LAN1上的主机A和局域网LAN2上的主机B通过互连的广域网WAN进行通信。我们知道,IP协议能够把源主机A发送出的分组,按照首部中的目的地址,送交到目的主机B,那么,为什么还需要运输层呢 ?
从IP层来说,通信的两端是两台主机。严格地讲,两台主机进行通信就是两台主机中的应用进程互相通信。IP协议虽然能把分组送到目的主机,但是这个分组还停留在主机的网络层而没有交付主机中的应用进程。从运输层的角度看,通信的真正端点并不是主机而是主机中的进程。也就是说,端到端的通信是应用进程之间的通信。
运输层提供应用进程间的逻辑通信”。“逻辑通信”的意思是:从应用层来看,只要把应用层报文交给下面的运输层,运输层就可以把这报文传送到对方的运输层(哪怕双方相距很远,例如几千公里),好像这种通信就是沿水平方向直接传送数据。但事实上这两个运输层之间并没有一条水平方向的物理连接。数据的传送是沿着图中的虚线方向(经过多个层次)传送的。
从这里可以看出网络层和运输层有明显的区别。网络层为主机之间提供逻辑通信,而运输层为应用进程之间提供端到端的逻辑通信(如下图)。
(TCP协议)传输控制协议是一种面向连接的、可靠的、基于字节流的方式进行有序的无差错的数据传输通讯协议,它负责完成传输层所指定的功能,利用重发技术和拥塞控制机制,向应用程序提供可靠的通信连接,使它能够自动适应网上的各种变化。比如:数据报检测、流量控制、拥塞控制、数据排序、超时重发等。
TCP是TCP/IP体系中非常复杂的一个协议。下面介绍TCP最主要的特点。
(1)TCP是面向连接的运输层协议。这就是说,应用程序在使用TCP协议之前,必须先建立TCP连接。在传送数据完毕后,必须释放已经建立的TCP连接。也就是说,应用进程之间的通信好像在“打电话”:通话前要先拨号建立连接,通话结束后要挂机释放连接。
(2)每一条TCP连接只能有两个端点(endpoint),每一条TCP连接只能是点对点的(一对一)。
(3)TCP提供可靠交付的服务。通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达。
(4)TCP提供全双工通信。TCP允许通信双方的应用进程在任何时候都能发送数据。TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。在发送时,应用程序在把数据传送给TCP的缓存后,就可以做自己的事,而TCP在合适的时候把数据发送出去。在接收时,TCP把收到的数据放入缓存,上层的应用进程在合适的时候读取缓存中的数据。
(5)面向字节流。TCP中的“流”(stream)指的是流入到进程或从进程流出的字节序列。“面向字节流”的含义是:虽然应用程序和TCP的交互是一次一个数据块(大小不等),但TCP把应用程序交下来的数据仅仅看成是一连串的无结构的字节流。TCP并不知道所传送的字节流的含义。TCP不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系(例如,发送方应用程序交给发送方的TCP共10个数据块,但接收方的TCP可能只用了4个数据块就把收到的字节流交付上层的应用程序)。但接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样。当然,接收方的应用程序必须有能力识别收到的字节流,把它还原成有意义的应用层数据。
每一条TCP连接有两个端点。那么,TCP连接的端点是什么呢?TCP连接的端点叫做套接字(socket)或插口。 定义:端口号拼接到(concatenated with)IP地址即构成了套接字。因此,套接字的表示方法是在点分十进制的IP地址后面写上端口号,中间用冒号或逗号隔开。例如,若IP地址是192.3.4.5而端口号是80,那么得到的套接字就是(192.3.4.5:80)。
套接字 socket = I P 地址 + port 端口号 = socket IP 地址 + port端口号
TCP连接 = {socket1, socker2} = {(IP1, port1), (IP2, port2)}
总之,TCP连接的端点是个很抽象的套接字,即(IP地址:端口号)。也应记住:同一个IP地址可以有多个不同的TCP连接,而同一个端口号也可以出现在多个不同的TCP连接中。
TCP报文段首部的前20个字节是固定的如下图,后面有4n字节是根据需要而增加的选项(n是整数)。因此TCP首部的最小长度是20字节。
部固定部分各字段的意义如下:
(1)源端口和目的端口 各占2个字节,分别写入源端口号和目的端口号,TCP的分用功能也是通过端口实现的。
(2)序号 占4字节。序号字段的值则指的是本报文段所发送的数据的第一个字节的序号。序号范围是[0,232–1],共232(即4 294 967 296)个序号。序号增加到232–1后,下一个序号就又回到0。也就是说,序号使用mod 232运算。TCP是面向字节流的。在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值则指的是本报文段所发送的数据的第一个字节的序号。例如,一报文段的序号字段值是301,而携带的数据共有100字节。这就表明:本报文段的数据的第一个字节的序号是301,最后一个字节的序号是400。显然,下一个报文段(如果还有的话)的数据序号应当从401开始,即下一个报文段的序号字段值应为401。这个字段的名称也叫做“报文段序号”。
(3)确认号 占4字节,是期望收到对方下一个报文段的第一个数据字节的序号。例如,B正确收到了A发送过来的一个报文段,其序号字段值是501,而数据长度是200字节(序号501~700),这表明B正确收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701。请注意,现在的确认号不是501,也不是700,而是701。
总之,应当记住:
若确认号=N,则表明:到序号N–1为止的所有数据都已正确收到。
由于序号字段有32位长,可对4GB(即4千兆字节)的数据进行编号。在一般情况下可保证当序号重复使用时,旧序号的数据早已通过网络到达终点了。
(4)数据偏移 占4位,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。这个字段实际上是指出TCP报文段的首部长度。由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的。但应注意,“数据偏移”的单位是32位字(即以4字节长的字为计算单位)。由于4位二进制数能够表示的最大十进制数字是15,因此数据偏移的最大值是60字节,这也是TCP首部的最大长度(即选项长度不能超过40字节)。
(5)保留 占6位,保留为今后使用,但目前应置为0。
下面有6个控制位,用来说明本报文段的性质,它们的释义见下面的(6)~(11)。
(6)紧急URG(URGent) 当URG=1时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据),而不要按原来的排队顺序来传送。例如,已经发送了很长的一个程序要在远地的主机上运行。但后来发现了一些问题,需要取消该程序的运行。因此用户从键盘发出中断命令(Control+C)。如果不使用紧急数据,那么这两个字符将存储在接收TCP的缓存末尾。只有在所有的数据被处理完毕后这两个字符才被交付接收方的应用进程。这样做就浪费了许多时间。
当URG置1时,发送应用进程就告诉发送方的TCP有紧急数据要传送。于是发送方TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据。这时要与首部中紧急指针(Urgent Pointer)字段配合使用。
(7)确认ACK(ACKnowledgment) 仅当ACK=1时确认号字段才有效。当ACK=0时,确认号无效。TCP规定,在连接建立后所有传送的报文段都必须把ACK置1。
(8)推送PSH(PuSH) 当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下,TCP就可以使用推送(push)操作。这时,发送方TCP把PSH置1,并立即创建一个报文段发送出去。接收方TCP收到PSH=1的报文段,就尽快地(即“推送”向前)交付接收应用进程,而不再等到整个缓存都填满了后再向上交付。
虽然应用程序可以选择推送操作,但推送操作很少使用。
(9)复位RST(ReSeT) 当RST=1时,表明TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。RST置1还用来拒绝一个非法的报文段或拒绝打开一个连接。RST也可称为重建位或重置位。
(10)同步SYN(SYNchronization) 在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使SYN=1和ACK=1。因此,SYN置为1就表示这是一个连接请求或连接接受报文。关于连接的建立和释放,在后面的5.9节还要进行详细讨论。
(11)终止FIN(FINis,意思是“完”、“终”) 用来释放一个连接。当FIN=1时,表明此报文段的发送方的数据已发送完毕,并要求释放运输连接。
(12)窗口 占2字节。窗口值是[0,216–1]之间的整数。窗口指的是发送本报文段的一方的接收窗口(而不是自己的发送窗口)。窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量(以字节为单位)。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。总之,窗口值作为接收方让发送方设置其发送窗口的依据。
例如,发送了一个报文段,其确认号是701,窗口字段是1000。这就是告诉对方:“从701号算起,我(即发送此报文段的一方)的接收缓存空间还可接收1000个字节数据(字节序号是701~1700),你在给我发送数据时,必须考虑到这一点。”
总之,应当记住:窗口字段明确指出了现在允许对方发送的数据量。窗口值经常在动态变化着。
(13)检验和 占2字节。检验和字段检验的范围包括首部和数据这两部分。和UDP用户数据报一样,在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。伪首部的格式与图5-5中UDP用户数据报的伪首部一样。但应把伪首部第4个字段中的17改为6(TCP的协议号是6),把第5字段中的UDP长度改为TCP长度。接收方收到此报文段后,仍要加上这个伪首部来计算检验和。若使用IPv6,则相应的伪首部也要改变。
(14)紧急指针 占2字节。紧急指针仅在URG=1时才有意义,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据)。因此,紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据都处理完时,TCP就告诉应用程序恢复到正常操作。值得注意的是,即使窗
TCP是面向连接的协议。运输连接是用来传送TCP报文的。TCP运输连接的建立和释放是每一次面向连接的通信中必不可少的过程。因此,运输连接就有三个阶段,即:连接建立、数据传送和连接释放。运输连接的管理就是使运输连接的建立和释放都能正常地进行。
在TCP连接建立过程中要解决以下三个问题:
(1)要使每一方能够确知对方的存在。
(2)要允许双方协商一些参数(如最大窗口值、是否使用窗口扩大选项和时间戳选项以及服务质量等)。
(3)能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配。
TCP连接的建立采用客户服务器方式。主动发起连接建立的应用进程叫做客户(client),而被动等待连接建立的应用进程叫做服务器(server)。
TCP建立连接的过程叫做握手,握手需要在客户和服务器之间交换三个TCP报文段。下图为客户端主动发起的图解:
首先主动打开连接的客户端结束CLOSED状态,被动打开的服务器端也结束CLOSED状态,并进入LISTEN状态。随后开始“三次握手”:
首先要明确下TCP握手的目的是为了通信,能够完成数据传输。那么通信的前提就是客户端和服务端都要具备读写能力。
第一次握手: 服务端收到客户端发来的请求(即第一次握手)能够证明客户端具备写的能力,
第二次握手:服务端给客户端进行回复信息(即第二次握手),客户端收到服务端回复的信息能够证明服务端具备读写的能力;
第三次握手:客户端发送给服务端最后一段报文(即第三次握手),服务端收到后能够证明客户端具备读的能力。
原因是为了防止服务端开启一些无用的连接增加服务器开销以及防止已失效的连接请求报文段突然又传送到了服务端而产生错误。“第三次握手”是客户端向服务端发送数据,目的是告诉服务器,客户端有没有收到服务器“第二次握手”时传过去的数据,若发送的是“收到了”的信号,服务端接收后就正常建立TCP连接,否则建立TCP连接失败,服务器关闭连接端口,由此减少服务器开销及防止接收到失效请求而导致错误
MSL即最长报文段寿命(Maximum Segment Lifetime),指任何报文在网络上存在的最长时间,超过该时间则报文被丢弃,一般MSL为30秒、1分钟等。
第一,为了保证客户端发送的最后一个ACK报文段能够到达服务端。这个ACK报文段有可能丢失,因而使处在LAST-ACK状态的服务端收不到对已发送的FIN+ACK报文段的确认。服务端会超时重传这个FIN+ACK报文段,而客户端就能在2MSL时间内收到这个重传的FIN+ACK报文段。接着A重传一次确认,重新启动2MSL计时器。最后,客户端和服务端都正常进入到CLOSED状态。如果A在TIME-WAIT状态不等待一段时间,而是在发送完ACK报文段后立即释放连接,那么就无法收到B重传的FIN+ACK报文段,因而也不会再发送一次确认报文段。这样,服务端就无法按照正常步骤进入CLOSED状态。
第二,已失效的连接请求报文段”出现在本连接中。客户端在发送完最后一个ACK报文段后,再经过时间2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。
服务端只要收到了客户端发出的确认,就进入CLOSED状态。同样,服务端在撤销相应的传输控制块TCB后,就结束了这次的TCP连接。我们注意到,服务端结束TCP连接的时间要比A早一些。
字段 | 含义 |
CLOSED | 关闭状态,表示当前主机没有正在运行的传输连接 |
LISTEN | 监听状态,表示服务器正在等待新的传输连接进入 |
SYN-RCVD | 表示主机已收到一个连接请求,但尚未确认 |
SYN-SENT | 表示主机已经发出一个连接请求,等待对方确认 |
ESTABLISHED | 传输连接建立,双方进入正常数据传输状态 |
FIN-WAIT-1 | (主动关闭)主机已经发送关闭连接请求,等待对方确认 |
FIN-WAIT-2 | (主动关闭)主机已收到对方关闭连接确认,等待对方发送关闭连接请求 |
TIMED WAIT | 完成双向传输连接关闭,等待所有分组消失 |
CLOSING | 双方同时尝试关闭传输连接,等待对方确认 |
CLOSE WAIT | (被动关闭)收到对方发来的关闭连接请求,并已确认 |
LAST ACK | 被动关闭)等待最后一个关闭连接确认,并等待所有分组消失 |