传输层
大纲要求
(一)传输层提供的服务
- 传输层的功能
- 传输层寻址与端口
- 无连接服务与面向连接服务
(二)UDP
- UDP 数据报
- UDP校验
(三)TCP
- TCP报文段
- TCP连接管理
- TCP可靠传输
- TCP流量控制与拥塞控制
核心考点
- (★★★★★)TCP的流量控制和拥塞控制机制
- (★★★★)TCP的连接和释放
- (★★★)TCP报文格式、UDP数据报格式
传输层提供的服务
传输层的功能
从通信和信息处理的角度看,传输层是5层参考模型中的第4层,它向上面的应用层提供通信服务。它属于面向通信部分的最高层,同时也是用户功能中的最低层。
传输层为两台主机提供了应用进程之间的通信,又称为端到端通值。由于网络层协议是不可靠的,会使分组丢失、失序和重复等,所以派出传输层为数据传输提供可靠的服务,如图 5-1 所示。
在图5-1中,整个主机可以看成是一栋寝室楼,而端口指出的那个小方块就可以看成是一个寝室,其中是一个个应用进程。
可能疑问点∶很多考生会问,既然传输层的UDP是不可靠的,为什么又说传输层提供可靠的服务?
解析∶某一层是否是可靠的,确实取决于这一层使用的是什么协议。例如,以前说数据链路层可靠,是因为链路层使用了HDLC协议。而现在因为一般在链路上传输不会出现错误,所以淘汰了HDLC 协议,都使用无连接的PPP(PPP和HDLC请参考数据链路层的讲解)。现在数据链路层又是不可靠的。当然,网络层也一样不可靠,因为使用了无连接的IP。
类推到传输层,由于现在的可靠传输交给数据链路层和网络层已经不可能,自然这份可靠的任务就落在了传输层身上。确实传输层中的UDP是不可靠的,因为使用UDP不能保证数据报都能正确地到达目的地,UDP发现错误之后可以选择丢弃,也可以选择向应用层报告错误。但是关键还是要由用户自己来选择,如果用户选择了TCP(如 FTP软件),自然传输层就是可靠的。但是,如果用户使用了UDP(如QQ软件、视频会议软件等),传输层就不可靠。所以说传输层是否可靠与传输层使用的协议有很大关系,但是一般默认传输层是可靠的。
传输层的功能如下∶
- 提供应用进程间的逻辑通信(网络层提供主机之间的逻辑通信)
"逻辑通信"的意思是传输层之间的通信好像是沿图5-2所示水平方向传送数据,但事实上这两个传输层之间并没有一条水平方向的物理连接。 - 差错检测
对收到报文的首部和数据部分都进行差错检测(网络层只检查IP数据报首部,并不检查数据部分)。 - 提供无连接或面向连接的服务
根据应用的不同,如有些数据传输要求实时性(如实时视频会议),传输层需要有两种不同的传输协议,即面向连接的TCP和无连接的UDP。TCP提供了一种可靠性较高的传输服务,UDP则提供了一种高效率的但不可靠的传输服务。 - 复用和分用
复用是指发送方不同的应用进程都可以使用同一个传输层协议传送数据。分用是指接收方的传输层在剥去报文的首部后能够把这些数据正确交付到目的应用进程。与在第3章讲解的4种多路复用原理上差不多,只是形式上改变了。
以上的功能是针对整个传输层而言的,而对于面向连接的服务还有以下两个功能。
- 连接管理
通常把连接的定义和建立的过程称为握手。例如,TCP的"三次握手"机制。 - 流量控制与拥塞控制
以对方和网络普遍接受的速度发送数据,从而防止网络拥塞造成数据的丢失。
疑问1∶在传输层应根据什么原则来确定使用面向连接服务还是无连接服务?
解析∶需要根据上层应用程序的性质来区分。
例如,在传送文件时要使用文件传送协议(FTP),而文件的传送必须是可靠的,不能有错误或者丢失,因此在传输层就必须使用面向连接的TCP。但是若应用程序是要传送分组话音或视频点播信息,那么为了保证信息传输的实时性,传输层就必须使用无连接的UDP。
疑问2∶应用进程看见的好像在两个传输层实体之间有一条端到端的逻辑通信信道,怎么理解?
故事助记∶例如,现在有两栋7层楼房,张三站在其中一栋的4楼,李四站在对面那栋楼房的4楼,并且招手示意让张三过去。根据常理,张三肯定必须先下到一楼,再从地面走向另外一栋楼,然后爬楼梯到4楼。没过一会儿,张三突然出现在李四的面前。在李四眼里,好像这两栋楼的第4层是相连的,可以直接走过来。其实不是这样,只是李四没有看到张三爬楼梯的细节而已。
疑问3∶TCP是面向连接的,但TCP使用的IP却是无连接的。这两种协议都有哪些主要的区别?
解析∶这个问题很重要,一定要弄清楚。TCP是面向连接的,但TCP所使用的网络则可以是面向连接的(如X.25 网络,已经淘汰,在此仅作为例子,不用了解)也可以是无连接的(如现在大量使用的IP网络)。选择无连接网络就使得整个系统非常灵活,当然也带来了一些问题。表5-1是TCP与IP向上提供的功能和服务的比较。
显然,TCP所提供的功能和服务要比IP所能提供的功能和服务多得多。这是因为TCP 使用了诸如确认、滑动窗口、计时器等机制,因而可以检测出有差错的报文、重复的报文和失序的报文。
传输层寻址与端口
端口的基本概念
前面讲过数据链路层按 MAC地址寻址,网络层按IP地址寻址,而传输层是按端口号寻址的。
端口就是传输层服务访问点,端口能够让应用层的各种应用进程将其数据通过端口向下交付给传输层以及让传输层知道应当将其报文段中的数据向上通过端口交付给应用层的相应进程。
从这个意义上讲,端口就是用来标识应用层的进程。换句通俗的话,端口就类似于寝室号,而寝室里面住着应用进程。
注意∶以上讲解的端口都是软件端口。
软件端口与硬件端口的区别∶硬件端口是不同硬件设备进行交互的接口(如交换机和路由器的端口),而软件端口是应用层的各种协议进程与传输实体进行层间交互的一种地址。
端口号
由于同一时刻一台主机上会有大量的网络应用进程在运行,所以需要有大量的端口号来标识不同的进程。
端口用一个16位端口号进行标识,共允许有216=65536个端口号。端口号只具有本地意义,即端口号只是为了标识本计算机应用层中的各进程。
例如,主机A的8080号端口和主机B的8080号端口是没有任何联系的。根据端口号范围可将端口分为3类。
-
熟知端口(保留端口)∶数值一般为0~1023。当一种新的应用程序出现时,必须为它指派一个熟知端口,以便其他应用进程和其交互。常见的几个熟知端口见表5-2。
-
登记端口∶数值为1024~49151。它是为没有熟知端口号的应用程序使用的,使用这类端口号必须在IANA 登记,以防止重复。
-
客户端端口或短暂端口∶数值为49152~65535。由于这类端口号仅在客户进程运行时才动态选择,所以称为短暂端口或临时端口。通信结束后,此端口就自动空闲出来,以供其他客户进程使用。
注意∶1)和2)又称为服务端端口。
套接字
一台拥有IP地址的主机可以提供许多服务,如Web服务、FTP服务、SMTP服务等,这些服务完全可以通过一个 IP地址来实现。
故事助记∶例如,A宿舍的一个同学要分别送不同的东西给B宿舍不同的同学,就类似使用Web服务、FTP服务、SMTP服务等多种服务。当然仅仅知道这些东西是送给B宿舍的同学是不够的,就好像只知道IP地址,所以说需要知道不同的东西送到B宿舍的哪个寝室(假设寝室都是单人间,住在这里面的人就相当于一个进程),寝室号码就类似端口号。因此,要确定一个东西送到哪里,需要宿舍号+寝室号。就好像如果要实现FTP服务就需要知道主机的IP地址和该应用程序的端口号,这样才能区分不同的服务。但是需要注意的是,端口并不是一一对应的。例如,你的计算机作为客户机访问一台WWW服务器时,WWW服务器使用"80"端口与你的计算机通信,但你的计算机则可能使用"50000"这样的端口。所以只有通过IP地址和端口号才能唯一确定一个连接的端口,称为套接字,即
套接字 =(主机IP地址,端口号)
它唯一地标识了网络中的某台主机上的某个应用进程。
无连接服务和面向连接服务
关于无连接服务与面向连接服务的基本概念请参考1.2.4小节。
传输层提供了两种类型的服务∶无连接服务和面向连接服务,相应的实现分别是用户数据报协议(UDP)和传输控制协议(TCP)。
当采用TCP时,传输层向上提供的是一条全双工的可靠的逻辑信道;
当采用UDP时,传输层向上提供的是一条不可靠的逻辑信道。
UDP的主要特点
- 传送数据前无需建立连接,数据到达后也无需确认。
- 不可靠交付。
- 报文头部短,传输开销小,时延较短。
TCP的主要特点
- 面向连接,不提供广播或多播服务。
- 可靠交付。
- 报文段头部长,传输开销大。
总结1∶UDP数据报与IP分组的区别。
解析∶IP分组要经过互联网中许多路由器的存储转发,但 UDP数据报是在传输层的端到端抽象的逻辑信道中传送的,UDP数据报只是IP数据报中的数据部分(见图 5-3),对路由器是不可见的。
总结 2∶TCP连接和网络层的虚电路的区别。
解析∶TCP报文段是在传输层抽象的端到端逻辑信道中传送的,对路由器不可见。TCP中所谓的连接只是在TCP的TCB(见下解释)中存储了对端的地址信息,并且记录连接的状态,通过重发之类来保证可靠传输,并没有一条真正的物理连接。而电路交换是真正建立一条物理连接,考生不要弄混。另外,虚电路建立的也不是一条真正的物理连接。
注意∶在网络传输层,TCP模块中有一个TCB(传输控制模块,Transmit Contol Block。它用于记录TCP运行过程中的变量。对于有多个连接的TCP,每个连接都有一个TCB。TCB 结构的定义包括这个连接使用的源端口、目的端口、目的IP、序号、应答序号、对方窗口大小、自己窗口大小、TCP状态等。
可能疑问点∶当应用程序使用面向连接的TCP和无连接的IP时,这种传输是面向连接的还是面向无连接的?
解析∶这个问题应该回答都是。因为这要从不同的层次来看,在传输层是面向连接的,而在网络层是面向无连接的。
UDP
UDP的数据报
UDP的基本概念
UDP和TCP最大的区别在于它是无连接的,UDP其实只在IP的数据报服务之上增加了端口的功能(为了找到进程)和差错检测的功能。
虽然UDP用户数据报只能提供不可靠的交付,但UDP在某些方面有其特殊的优点。
- 发送数据之前不需要建立连接。
- UDP的主机不需要维持复杂的连接状态表。
- UDP用户数据报只有8个字节的首部开销。
- 网络出现的拥塞不会使源主机的发送速率降低(没有拥塞控制)。这对某些实时应用(如IP电话、实时视频会议)是很重要的。
- UDP支持一对一、一对多、多对一和多对多的交互通信。
UDP数据报的组成
UDP数据报有两个字段∶数据字段和首部字段。首部字段有8B,由4个字段组成,如图5-4所示。
-
源端口∶占2B。前面已经说了使用16bit来表示端口号,所以需要2B长度。
-
目的端口∶占2B。
-
长度∶占2B。
注意∶尽管使用2B来描述UDP数据报的长度,但是一般来说UDP限制其应用程序数据为512B或更小。 -
校验和∶占2B,用来检测UDP用户数据报在传输中是否有错(既检验首部,又检验数据部分),如果有错,就直接丢弃。若该字段为可选字段,当源主机不想计算校验和时,则直接令该字段为全0。
检验范围∶伪首部、UDP数据报的首部和数据。其中,在计算校验和时临时生成伪首部。
具体校验和的计算方法参考5.2.2小节。
UDP校验
UDP校验只提供差错检测。在计算校验和时,要在 UDP用户数据报之前临时加上 12B 的伪首部,如图 5-4所示。
其中,伪首部包括源IP地址字段、目的IP地址字段、全0字段、协议字段(UDP固定为17)、UDP长度字段(图5-5假设用户数据报的长度是15B)。一定要记住伪首部只用于计算和验证校验和,其既不向下传送,也不向上递交。
注意∶
- 校验的时候若UDP数据报数据部分的长度不是偶数字节,则需要填入一个全0字节,如图5-5所示。但是此字节和伪首部一样,是不发送的。
- 如果UDP校验和校验出UDP数据报是错误的,可以丢弃,也可以交付给上层,但是=需要附上错误报告==,即告诉上层这是错误的数据报。
- 通过伪首部,不仅可以检查源端口号、目的端口号和UDP用户数据报的数据部分,还可以检查IP数据报的源IP地址和目的地址。
不难看出,图5-5 这种简单的差错检验方法的检错能力并不强,但它的好处是简单,处理起来较快。
按二进制反码计算后,当无差错时其结果应该为全1;否则就表明有差错出现,接收方就应该丢弃这个 UDP报文。
可能疑问点∶什么是按二进制反码运算求和?
以上答案其实是错误的,由于最高位产生了进位,所以要对最后的结果加1,最后的答案应该为0011011011001101。
TCP
TCP报文段
最麻烦的知识点来了,不是说它难,而是很快就容易忘记,希望下面的总结能帮助快速记住TCP报文段的各个字段含义。
在讲IP数据报的时候,讲过IP数据报分为首部和数据部分,IP数据报的功能全部体现在首部,而TCP报文段也分为首部和数据两部分。
同理,TCP的全部功能也都体现在首部的各个字段中,所以重点讲解 TCP报文段的首部。讲解首部之前,还是先声明一点∶讲解IP 数据报时就说过,首部默认是20B(如果题目中没有说明),不要认为是60B,记忆方式和IP 数据报类似,TCP报文段也用4位表示首部长度,所以可以表示15个单位的长度(0000不包括),然后根据记忆方式∶首饰=首4,即最小单位是4B,所以可以表示60B的长度,在IP 数据报中称为首部长度,而在TCP报文段中称为数据偏移。下面对照图5-6所示TCP报文的首部格式详细讲解各个字段。
-
源端口和目的端口∶各占2B。与UDP一样,TCP的首部当然也有源端口和目的端口。
-
序号∶占4B。尽管从应用层交付下来的是TCP报文段,但是TCP是面向字节流的(就是说TCP传送时是按照一个个字节来传送的),所以在一个TCP连接中传送的字节流需要编号,这样才能保证按序交付。
如,某报文段的序号从301开始,而携带的数据共有100B。这就表明本报文段数据的第一个字节的序号是301,最后一个字节的序号是400。显然,下一个报文段(如果还有)的数据序号应当从401开始,即下一个报文段的序号字段应为401,这个字段名也称为"报文段序号"。
-
确认号∶占4B。TCP是含有确认机制的,所以接收端需要给发送端发送确认号,这个确认号只需记住一点∶若确认号等于N,则表明到序号N-1为止的所有数据都已经正确收到。
例如,B正确收到了A发送过来的一个报文段,其序号字段值是501,而数据长度是200B (序号501~700),这表明B正确收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B将发送给A的确认报文段中的确认号设置为701。注意,现在的确认号不是501,也不是700,而是701。
-
数据偏移∶占4位。前面已经讲过,这里的数据偏移不是IP数据报中分片的那个数据偏移,而是表示首部长度,千万不要混淆。占4位可表示0001~1111一共15种状态,而基本单位是4B,所以数据偏移确定了首部最长为60B。
-
保留字段∶占6位。保留为今后使用,但目前应置为0,该字段可以忽略不计。
-
紧急 URG∶当URG=1时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。就好像有一个等待红灯的超长车队,此时有一辆救护车过来,属于紧急事件,救护车就可以不用等红灯了,直接从边上绕过所有的车。但是紧急URG需要和紧急指针配套使用,比如说有很多救护车过来,现在就需要一个紧急指针指向最后一辆救护车,一旦最后一辆救护车过去之后,TCP就告诉应用程序恢复到正常操作,也就是说数据从第一字节到紧急指针所指字节就是紧急数据。
-
确认比特ACK∶只有当ACK=1时,确认号字段才有效;当ACK=0时,确认号无效。TCP规定,一旦连接建立了,所有传送的报文段都必须把 ACK置1。
-
推送比特PSH∶TCP收到推送比特置1的报文段,就尽快地交付给接收应用进程,而不再等到整个缓存都填满后再向上交付。
可能疑问点∶看到这里肯定有考生会有这样的疑惑,在TCP首部中,URG是紧急比特,而当URG=1时,表示紧急指针有效,也就是能发送紧急数据。而PSH的目的也是发送紧急数据,那么 URG和PSH到底有什么区别?
解析∶URG=1,表示紧急指针指向报文内数据段的某个字节(数据从第一字节到指针所指字节就是紧急数据),不进入接收缓冲(前面讲了待上交的数据要先进入接收缓存,然后再交付给应用层。而这里就直接交给上层进程,余下的数据都是要进入接收缓冲的)。一般来说,TCP是要等到整个缓存都填满了后再向上交付,如果PSH=1,就不用等到整个缓存都填满,直接交付,但是这里的交付仍然是从缓冲区中交付的,URG是不经过缓冲区的,千万记住。
-
复位比特RST∶当RST=1时,表明TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立传输连接。
-
同步比特SYN∶同步比特SYN置为1,表示这是一个连接请求或连接接受报文,后面TCP连接会详细讲到。
-
终止比特FIN∶释放一个连接。当FIN=1时,表明此报文段的发送端的数据已发送完毕,并要求释放传输连接。
-
窗口字段∶占2B。窗口字段用来控制对方发送的数据量,单位为字节(B)。记住一句话∶窗口字段明确指出了现在允许对方发送的数据量。
例如,设确认号是701,窗口字段是1000。这就表明,从701号开始算起,发送此报文段的一方还有接收1000B数据的接收缓存空间。
-
校验和字段∶占2B。校验和字段检验的范围包括首部和数据两部分。在计算校验和时,和UDP一样,要在TCP报文段的前面加上12B的伪首部(只需将UDP伪首部的第4个字段的17改为6,其他和UDP一样)。
-
紧急指针字段∶占2B。前面已经讲过紧急指针指出在本报文段中的紧急数据的最后一个字节的序号。
-
选项字段∶长度可变。TCP最初只规定了一种选项,即最大报文段长度MSS。MSS 告诉对方TCP∶"我的缓存所能接收的报文段的数据字段的最大长度是MSS字节。"
-
填充字段∶为了使整个首部长度是4B的整数倍。
可能疑问点∶在TCP报文段的首部中只有端口号而没有IP地址。当TCP将其报文段交给IP层时,IP怎样知道目的IP地址呢?
解析∶显然,仅从TCP报文段的首部是无法得知目的IP地址的。因此,TCP必须告诉IP层此报文段要发送给哪一个目的主机(给出其IP地址)。此目的IP地址填写在IP数据报的首部中。
TCP的连接管理
TCP的传输连接分为3个阶段∶连接建立、数据传送和连接释放。
TCP传输连接的管理就是使传输连接的建立和释放都能正常地进行。
TCP把连接作为最基本的抽象,每一条TCP连接有两个端点,TCP连接的端点不是主机,不是主机的IP地址,不是应用进程,也不是传输层的协议端口。TCP连接的端点叫作套接字(Socket)或插口。端口号拼接到IP地址即构成了套接字。
每一条 TCP连接唯一地被通信两端的两个端点(两个套接字)所确定。
例如,TCP连接∶={socket1,socket2)={(IP1∶port1),(IP2∶port2)}。
TCP的连接和建立都是采用客户/服务器方式。
主动发起连接建立的应用进程叫作客户(Client),被动等待连接建立的应用进程叫作服务器(Server)。
TCP传输连接的建立采用"三次握手"的方法,如图5-7所示。下面从一个实例来分析建立连接的过程。
-
第一步∶客户机A的TCP向服务器B发出连接请求报文段,其首部中的同步位SYN=1(TCP规定,SYN报文段不能携带数据,但要消耗一个序号),并选择序号seq=x,表明传送数据时的第一个数据字节的序号是x。
-
第二步∶服务器收到了数据报,并从SYN位为1知道这是一个建立连接的请求。如果同意,则发回确认。B在确认报文段中应使SYN=l,ACK=1,其确认号ack=x+1,自己选择的序号seq=y。注意,此时该报文段也不能携带数据(助记∶因为有SYN=1,所以不能带数据)。
-
第三步∶A收到此报文段后向B给出确认,其ACK=1,确认号ack=y+1。A的TCP通知上层应用进程,连接已经建立。B的TCP收到主机A的确认后,也通知其上层应用进程,此时TCP连接已经建立,ACK 报文可以携带数据(没有SYN字段),如果不携带数据则不消耗序号。
采用"三次握手"的方法,目的是为了防止报文段在传输连接建立过程中出现差错。通过3次报文段的交互后,通信双方的进程之间就建立了一条传输连接,然后就可以用全双工的方式在该传输连接上正常地传输数据报文段了,下面先看两个例子。
解析∶C。不管是连接还是释放,SYN、ACK、FIN的值一定是1,排除A和D选项。确认号是甲发送的序列号加1,ack 的值应该为11221(11220已经收到,期待接收11221。另外需要提醒的一点是,乙的seq 值是主机随意给的,和甲的seq值没有任何关系,请参考下面的总结。
解析∶B。首先应该计算出第2个段的第1个字节的序号。第3个段的第1个字节序号为900,由于第2个段有400B,所以第2个段的第1个字节的序号为500。
另外,由于确认号就是期待接收下一个TCP段的第1个字节序号,所以主机乙发送给主机甲的确认序号是500一旦数据传输结束,参与传输的任何一方都可以请求释放传输连接。
在释放连接过程中,发送端进程与接收端进程要通过4次TCP报文段来释放整个传输连接,在此分成4步来详细讲解。
第一步∶如图5-8所示,数据传输结束后,通信双方都可释放连接。现在A的应用进程先向其TCP发出连接释放报文段,并停止再发送数据,主动关闭TCP连接。A将连接释放报文段首部的FIN 置1,其序号seq=u,等待B的确认。这里要注意,因为TCP是双工的,也就是说,可以想象一对TCP连接上有两条数据通路。当发送FIN报文时,发送FIN的一端就不能发送数据,也就是关闭了其中一条数据通路,但是对方还是可以发送数据的。
第二步∶如图5-9所示,B发出确认,确认号ack=u+1,而这个报文段自己的序号seq=v。TCP服务器进程通知高层应用进程。从A到B这个方向的连接就释放了,TCP连接处于半关闭状态。B若发送数据,则A 仍要接收。
第三步∶如图5-10所示,若B已经没有要向A发送的数据,其应用进程就通知TCP释放连接。
第四步∶如图5-11所示,A收到连接释放报文段后,必须发出确认。在确认报文段中,ACK=1,确认号ack=w+1,自己的序号seq=u+1。
提醒∶TCP连接必须经过时间 2MSL后才真正释放,如图5-12所示。
总结∶
(1)连接建立分为3步∶
- SYN=1,seq=x。
- SYN=1,ACK=1,seq=y,ack=x+1。
- ACK=1,seq=x+1,ack=y+1。
(2)连接释放分为4步∶
- FIN=1,seq=u。
- ACK=1,seq=v,ack=u+1。
- FIN=1,ACK=1,seq=w,ack=u+1。
- ACK=1,seq=u+1,ack=w+1。
可能疑问点∶为什么TCP在建立连接时不能每次都选择相同的、固定的初始序号?
解析∶如果TCP在建立连接时每次都选择相同的、固定的初始序号,那么设想以下的情况。
- 假定主机A和B频繁地建立连接,传送一些TCP报文段后,再释放连接,然后又不断地建立新的连接、传送报文段和释放连接。
- 假定每一次建立连接时,主机A都选择相同的、固定的初始序号,如选择1。
- 假定主机A发送出的某些TCP报文段在网络中会滞留较长的时间,以致造成主机A 超时重传这些TCP报文段。
- 假定有一些在网络中滞留时间较长的TCP报文段最后终于到达了主机 B,但这时传送该报文段的那个连接早已释放了,而在到达主机B时的TCP连接是一条新的TCP连接。
这样,工作在新的TCP连接下的主机B就有可能会接收在旧的连接传送的、已经没有意义的、过时的TCP报文段(因为这个TCP报文段的序号有可能正好处在现在新的连接所使用的序号范围之中),结果产生错误。
因此,必须使得迟到的TCP报文段的序号不处在新的连接所使用的序号范围之中。这样,TCP在建立新的连接时所选择的初始序号一定要和前面的一些连接所使用过的序号不一样。因此,不同的TCP连接不能使用相同的初始序号。
可能疑问点∶为什么不采用"两次握手"建立连接?
解析∶"三次握手"完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
如果把"三次握手"改成"两次握手",就可能发生死锁。
例如,考虑计算机A和B之间的通信,假定A给B发送一个连接请求分组,B收到了这个分组,并发送了确认应答分组。按照"两次握手"的协定,B认为连接已经成功地建立了,可以开始发送数据分组。可是,A 在B的应答分组在传输中被丢失的情况下,将不知道B是否已准备好,也不知道B发送数据使用的初始序列号,A甚至怀疑B是否收到自己的连接请求分组。在这种情况下,A认为连接还未建立成功,将忽略B发来的任何数据分组,只等待连接确认应答分组。而B在发出的分组超时后,重复发送同样的分组。这样就形成了死锁,如图5-13所示。
可能疑问点∶为什么不采用"三次握手"释放连接,且发送最后"一次握手"报文后要等待2MSL(最长报文寿命)的时间呢?
解析∶首先,为了保证A发送的最后一个确认报文段能够到达B。如果A不等待2MSL,A返回的最后确认报文段丢失,则B不能进入正常关闭状态,而A此时已经关闭,也不可能再重传。
其次,防止出现"已失效的连接请求报文段"。A在发送完最后一个确认报文段后,再经过2MSL可保证本连接持续的时间内所产生的所有报文段从网络中消失。造成错误的情形与上文不采用"两次握手"建立连接的原因所述的情形相同。
TCP可靠传输
滑动窗口机制在第3章已经详细讲解过,在此不再重复讲解。下面仅做一个简单的总结。
TCP数据编号与确认
TCP是面向字节的。TCP将所要传送的报文看成是字节组成的数据流,并使每一个字节对应于一个序号。在连接建立时,双方要商定初始序号。TCP每次发送的报文段的首部中的序号字段数值表示该报文段中的数据部分的第一个字节的序号。
TCP的确认是对接收到的数据的最高序号表示确认。接收端返回的确认号是已收到的数据的最高序号加1。因此,确认号表示接收端期望下次收到的数据中的第一个数据字节的序号。
补充知识点∶选择确认 SACK。
解析∶不知道大家还记不记得,在讲解连续 ARQ协议时,将其分为后退N帧协议和选择重传协议。
在后退N帧协议中,如果帧不按序到达,直接丢弃后面的,没有使用选择确认。在选择重传协议中,先把后面有序的帧存在接收缓冲区中,等到前面失序的帧到达后,一起按序交付,这里就用到选择确认 SACK。
可能疑问点∶在使用TCP传送数据时,如果有一个确认报文段丢失了,那么会不会一定引起对方数据的重传?
解析∶如果使用了累积确认就不一定。例如,现在采用累积确认,A发送了1、2、3、4、5号帧给B,但是ACK3丢失了(1和2号帧都接收到了,期望接收到3号帧),此时发送方正准备重发1和2号帧,却接收到了ACK6,也就是1~5号帧对方都收到了,所以就不要重发了。
TCP的重传机制
TCP每发送一个报文段,就对这个报文段设置一次计时器。只要计时器设置的重传时间到了规定时间还没有收到确认,那么就要重传该报文段。
由于TCP的下层是一个互联网环境,IP数据报所选择的路由变化很大,所以传输层的往返时延的方差也很大。为了计算超时计时器的重传时间,TCP采用了一种自适应的算法。
-
记录每个报文段发出的时间以及收到相应的确认报文段的时间。这两个时间之差就是报文段的往返时延。
-
将各个报文段的往返时延样本加权平均,就得出报文段的平均往返时延(RTT)。
-
每测量到一个新的往返时延样本,就按下式重新计算一次平均往返时延。
RTT=(1-a)x(旧的RTT)+a x(新的往返时延样本)
在上式中,0≤a<1。若a很接近于1,表示新算出的平均往返时延RTT和原来的值相比变化较大,即RTT的值更新较快。若选择α接近于0,则表示加权计算的RTT受新的往返时延样本的影响不大,即RTT的值更新较慢,一般推荐a取0.125。
计时器的超时重传时间(RTO)应略大于上面得出的RTT,即
RTO=βxRTT(其中β>1)
注意∶谢希仁的教材有更复杂求RTO的公式,都无须掌握,只需知道计时器的RTO应略大于上面得出的RTT即可。
补充知识点∶Karn算法。
解析∶当出现超时,源主机在重传报文段后,收到了确认报文段,但该确认报文段有可能是对后来重传报文段的确认,也有可能是对先前发送报文段的确认,如何进行判定?
由于重传的报文段和原来的报文段完全一样,所以源主机在收到确认后就无法做出正确的判定,而正确的判定与确定加权 RTT的值关系很大。
Kam提出了一个算法∶在计算加权RTT时,==只要报文段重传了,就不采用其作为往返时间样本。这样得出的加权 RTT和RTO就较准确。
修正的Kam算法∶报文段每重传一次,就把RTO增大一些。
新的RTO= y x(旧的RTO)
系数y的典型值是2。当不再发生报文段的重传时,才根据报文段的往返时延更新加权RTT 和RTO的数值。
可能疑问点∶是否TCP和UDP都需要计算往返时间RTT?
解析∶往返时间RTT只是对传输层的TCP很重要,因为TCP要根据RTT的值来设置超时计时器的超时时间。
UDP没有确认和重传机制,因此RTT对 UDP没有什么意义。
因此,不要笼统地说"往返时间RTT对传输层来说很重要",因为只有TCP才需要计算RTT,而UDP不需要计算RTT。
可能疑问点∶假定在一个互联网中,所有的链路的传输都不出现差错,所有的节点也都不会发生故障。试问在这种情况下,TCP的"可靠交付"的功能是否就是多余的?
解析∶不是多余的。TCP的"可靠交付"功能在互联网中起着至关重要的作用。至少在以下所列举的情况下,TCP的"可靠交付"功能是必不可少的。
- 每个IP数据报独立地选择路由,因此在到达目的主机时有可能出现失序。
- 由于路由选择的计算出现错误,导致IP数据报在互联网中转圈。最后数据报首部中的生存时间TTL的数值下降到零,这个数据报在中途就被丢弃了。
- 在某个路由器突然出现很大的通信量,以致路由器来不及处理到达的数据报,因此有的数据报被丢弃。
以上列举的问题表明,必须依靠TCP的"可靠交付"功能才能保证在目的主机的目的进程中收到正确的报文。
TCP流量控制
一般来说,人们总是希望数据传输得更快一些。但如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失。
流量控制(Flow Control)就是让发送方的发送速率不要太快,既要让接收方来得及接收,也不要使网络发生拥塞。利用滑动窗口机制可以很方便地在TCP连接上实现流量控制,请看图5-14所示的例子。
注意∶
- TCP为每一个连接设有一个持续计时器。只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器。若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带1B的数据),而对方就在确认这个探测报文段时给出了现在的窗口值。若窗口仍然是零,则收到这个报文段的一方就重新设置持续计时器。若窗口不是零,则死锁的僵局就可以打破了。
- 可以用不同的机制来控制TCP报文段的发送时机。
第一种机制∶TCP维持一个变量,它等于最大报文段长度(MSS)。只要缓存中存放的数据达到MSS字节时,就组装成一个TCP报文段发送出去。
第二种机制∶由发送方的应用进程指明要求发送报文段,即TCP支持的推送(push)操作(前面将其和紧急指针做过比较,这里不再解释)。
第三种机制∶发送方的一个计时器期限到了,这时就把当前已有的缓存数据装入报文段(但长度不能超过MSS)发送出去。
解析∶D。ACKn的意思是前n-1号的帧都已经收到,请发送方继续发送第n号帧。在本题中,主机甲发送的第一个段的序号为200~499,第二个段的序列号为500~999,主机乙正确接收到两个段后,应该希望主机甲接下来发送1000号帧,所以主机乙发送给主机甲的确认序列号是1000。
TCP拥塞控制的基本概念
在某段时间,若对网络中某资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏———产生拥塞(Congestion)。出现资源拥塞的条件是
对资源需求的总和>可用资源
若网络中产生拥塞,网络的性能就要明显变坏,整个网络的吞吐量将随输入负荷的增大而下降。
拥塞控制与流量控制的性质对比∶
- 拥塞控制所要做的只有一个目的,就是使得网络能够承受现有的网络负荷。
- 拥塞控制是一个全局性的过程,涉及所有的主机、所有的路由器以及与降低网络传输性能有关的所有因素。
- 流量控制往往指在给定的发送端和接收端之间的点对点通信量的控制。
- 流量控制所要做的就是抑制发送端发送数据的速率,以便使接收端来得及接收。
- 拥塞控制是很难设计的,因为它是一个动态的(而不是静态的)问题。
- 当前网络正朝着高速化的方向发展,这很容易出现缓存不够大而造成分组的丢失。但分组的丢失是网络发生拥塞的征兆而不是原因。
- 在许多情况下,正是拥塞控制本身成为引起网络性能恶化甚至发生死锁的原因,这点应特别引起重视。
拥塞控制又分为闭环控制和开环控制。
-
开环控制方法就是在设计网络时事先将有关发生拥塞的因素考虑周到,力求网络在工作时不产生拥塞。
-
闭环控制是基于反馈环路的概念。属于闭环控制的有以下几种措施∶
①监测网络系统以便检测到拥塞在何时、何处发生。
②将拥塞发生的信息传送到可采取行动的地方。
③调整网络系统的运行以解决出现的问题。
以上是拥塞控制的一些基本概念,下面详细讲解拥塞控制的方法。
拥塞控制的4种算法
发送端的主机在确定发送报文段的速率时,既要根据接收端的接收能力,又要从全局考虑不要使网络发生拥塞。因此,TCP要求发送端维护以下两个窗口。
- 接收端窗口rwnd∶接收端根据其目前接收缓存大小所许诺的最新的窗口值,反映了接收端的容量。由接收端将其放在TCP报文的首部的窗口字段通知发送端,如图5-14所示。
- 拥塞窗口cwnd∶发送端根据自己估计的网络拥塞程度而设置的窗口值,反映了网络的当前容量。
发送端发送窗口的上限值应当取接收端窗口rwnd和拥塞窗口cwnd这两个变量中较小的一个,即应按以下公式确定∶发送窗口的上限值=Min 【rwnd,cwnd】
从这个式子可以看出∶
当rwnd<cwnd时,发送窗口的上限值是接收方的接收能力限制发送窗口的最大值。
反之,当cwnd<rvnd时,发送窗口的上限值是网络的拥塞限制发送窗口的最大值。
也就是说,rwnd和cwnd中较小的一个控制发送方发送数据的速率。
注意∶接收方总是有足够大的缓存空间,因而发送窗口的大小由网络的拥塞程度来决定,也就是说可以将发送窗口等同为拥塞窗口。
解析∶A。发送窗口的上限值=Min{接收窗口,拥塞窗口},于是此时发送方的发送窗口=Min{4000,2000}=2000B,而主机甲向主机乙连续发送两个最大段后,只收到第一个段的确认,所以此时主机甲还可以向主机乙发送的最大字节数为2000B-1000B=1000B。
接收窗口的大小可以根据TCP报文首部的窗口字段通知发送端,而发送端怎么去维护拥塞窗口呢?
这就是下面要讲解的慢开始算法和拥塞避免算法。
慢开始算法的原理
- 在主机刚刚开始发送报文段时可先设置拥塞窗口cwnd=1,即设置为一个最大报文段长度 MSS的数值。
- 在每收到一个对新的报文段的确认后,将拥塞窗口加1,即增加一个MSS的数值。注意∶这里是说每收到1个对新的报文段的确认后,将拥塞窗口加1,而第二次会收到2 个确认,第三次会收到4个确认,依此类推,可以知道每经过一个传输轮次,拥塞窗口就加倍,如图5-15所示。
- 用这样的方法逐步增大发送端的拥塞窗口 cwnd,可以使分组注入到网络的速率更加合理。
补充知识点∶什么是传输轮次?
解析∶使用慢开始算法后,每经过一个传输轮次,拥塞窗口 cwnd就加倍。一个传传输轮次所经历的时间其实就是往返时间RTT。传输轮次更加强调把拥塞窗口cwnd所允许发送的报文段都连续发送出去,并收到了对已发送的最后一个字节的确认。
例如,拥塞窗口 cwnd=4,这时的往返时间RTT就是发送方连续发送4个报文段并收到这4个报文段的确认总共经历的时间。
使用慢开始算法后,每经过一个传输轮次,拥塞窗口cwnd就加倍,即 cwnd的大小呈指数形式增长。这样慢开始一直把拥塞窗口 cwnd 增大到一个规定的慢开始门ssthresh(阈值),然后改用拥塞避免算法。
拥塞避免算法的原理
为防止拥塞窗口 cwnd 的增长引起网络阻塞,还需要一个状态变量,即慢开始门限ssthresh,其用法如下∶
当cwnd<ssthresh时,使用慢开始算法。
当cwnd>ssthresh时,停止使用慢开始算法,改用拥塞避免算法。
cwnd=ssthresh 时,既可以使用慢开始算法,也可以使用拥塞避免算法。
其中,拥塞避免算法的做法是,发送端的拥塞窗口cwnd每经过一个往返时延RTT就增加一个MSS的大小,通常表现为按线性规律增长。
无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没按时收到确认),就要把慢开始门限ssthresh设置为出现拥塞时的发送窗口值的一半(但不能小于2),然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。
这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。以上具体过程通过下面一系列过程图来详细讲解。
-
当TCP连接进行初始化时,将拥塞窗口设置为1,如图5-16所示。图中的窗口单位不使用字节而使用报文段。慢开始门限的初始值设置为16个报文段,即ssthresh=16。发送端送窗口不能超过拥塞窗口 cwnd和接收端窗口 rwnd中的最小值。假定接收端窗口足够因此现在发送窗口的数值=等于拥塞窗口的数值==。
-
在执行慢开始算法时,拥塞窗口cwnd的初始值为1,发送第一个报文段M,如图5-17 所示。
-
发送端每收到一个确认,就把cwnd加1,于是发送端可以接着发送M1和M2两个报文段,如图5-18所示。
-
接收端共发回两个确认。发送端每收到一个对新报文段的确认,就把发送端的cwnd 加1。现在cwnd从2增大到4,并可接着发送后面的4个报文段,如图5-19所示。
5.
-
发送端每收到一个对新报文段的确认,就把发送端的拥塞窗口加1,因此拥塞窗口cwnd 随着传输轮次按指数规律增长,如图5-20所示。
-
当拥塞窗口cwnd增长到慢开始门限值 ssthresh 时(当cwnd=16时),就改为执行拥塞避免算法,拥塞窗口按线性规律增长,如图5-21所示。
-
假定拥塞窗口的数值增长到24时,网络出现超时,表明网络拥塞了,如图5-22所示。
- 更新后的ssthresh 值变为12(发送窗口数值24的一半),拥塞窗口重新设置为1,并执行慢开始算法,如图5-23所示。
- 当cwnd=12时改为执行拥塞避免算法,拥塞窗口按线性规律增长,每经过一个往返时延就增加一个MSS的大小,如图5-24所示。
总结∶
-
乘法减小。它是指不论在慢开始阶段还是拥塞避免阶段,只要出现一次超时(出现一次网络拥塞),就把慢开始门限值ssthresh设置为当前的拥塞窗口值的一半。当网络频繁出现拥塞时,ssthresh值就下降得很快,以减少注入到网络中的分组数。
-
加法增大。它是指执行拥塞避免算法时,在收到对所有报文段的确认后(经过一个往返时间),就把拥塞窗口 cwnd增加一个MSS 大小,使拥塞窗口缓慢增大,以防止网络过早出现拥塞。
-
拥塞避免并非指完全能够避免了拥塞。利用以上的措施要完全避免网络拥塞还是不可能的。拥塞避免是说在拥塞避免阶段把拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞。
解析∶C。当拥塞窗口为16KB时发生了超时,慢开始门限值将变成 8KB,发送窗口变为 1KB。
下面逐一列出各个 RTT之后的拥塞窗口大小。
- 开始重传∶此时拥塞窗口为1KB。
- 第一次RTT结束∶执行慢开始算法,此时拥塞窗口为2KB。
- 第二次RTT结束∶执行慢开始算法,此时拥塞窗口为4KB。
- 第三次RTT结束∶执行慢开始算法,此时拥塞窗口为8KB。
- 第四次RTT结束∶由于第三次RTT结束的时候拥塞窗口的大小已经和慢开始门限值相等,因此此时应该结束使用慢开始算法,转而使用拥塞避免算法,故此时拥塞窗口为8KB+1KB=9KB。
快重传算法
首先要求接收方每收到一个失序的报文段后就立即发出重复确认。这样做可以让发送方及早知道有报文段没有到达接收方。发送方只要连续收到3个重复确认就应当立即重传对方尚未收到的报文段,如图5-25所示。不难看出,快重传并非取消重传计时器,而是在某些情况下可更早地重传丢失的报文段。
快恢复算法
- 当发送端收到连续3个重复的确认时,就执行"乘法减小"算法,把慢开始门限ssthresh 设置为当前拥塞窗口的一半。但接下去不执行慢开始算法。
- 由于发送方现在认为网络很可能没有发生拥塞,所以现在不执行慢开始算法,即拥塞窗口cwnd现在不设置为1,而是将慢开始门限ssthresh设置为当前拥塞窗口的一半,然后开始执行拥塞避免算法("加法增大"),使得拥塞窗口缓慢地线性增大,如图5-26所示。
快恢复具体算法如下∶
- 当发送端收到连续3个重复的ACK时,就重新设置慢开始门限stresh(拥塞窗口的一半)。
- 与慢开始的不同之处是拥塞窗口cwnd不是设置为1,而是设置为新的sthresh。
- 若发送窗口值还允许发送报文段,就按拥塞避免算法继续发送报文段。
补充知识点∶有些快重传实现用的是另一种算法,考试的时候肯定会说明,为了全面地复习,所以将另一种算法也罗列出来,仅供参考,算法如下∶
- 当发送端收到连续3个重复的ACK时,就重新设置慢开始门限ssthresh(拥塞窗口的一半)。
- 与慢开始的不同之处是拥塞窗口 cwnd 不是设置为1,而是设置为 ssthresh+3 x MSS。
- 若收到的重复的ACK为n个(n>3),则将cwnd设置为ssthresh+ n x MSS。
- 若发送窗口值还允许发送报文段,就按拥塞避免算法继续发送报文段。