本章讨论TCP/IP体系中运输层最重要的两种协议:UDP和TCP。必须弄清TCP的各种机制(如面向连接的可靠服务、流量控制、拥塞控制等),以及TCP连接管理和状态图的概念。
一、运输层协议概述
1.进程之间的通信
IP协议是把分组送到目的主机,但这个分组还停留在主机的网络层而没有交付给主机中的应用进程。从运输层角度看,通信的真正端点并不是主机而是主机中的进程。
复用(multiplexing)——发送方不同的应用进程都可以使用同一个运输层协议传送数据(当然需要加上适当的首部)
分用(demultiplexing)——接收方的运输层在剥去报文的首部后能够把这些数据正确交付到目的应用进程。
运输层提供应用进程间的逻辑通信:指运输层之间的通信好像是沿水平方向传送数据,但事实上这两个运输层之间并没有一条水平方向的物理连接。要传送的数据是沿着图中的虚线方向(经过多个层次)传送的。
运输层还要对收到的报文进行差错检测。在网络层,IP数据报首部中的检验和字段,只检验首部是否出现差错而不检查数据部分。
两种不同协议:①面向连接的TCP:尽管下面的网络是不可靠的(只提供尽最大努力服务),但这种逻辑通信信道就相当于一条全双工的可靠信道。②无连接的UDP协议:仍是不可靠信道。
2.运输层的两个主要协议
(1)用户数据报协议UDP(user datagram protocol)
在传送数据之前不需要先建立连接,远地主机的运输层在收到UDP报文后,不需要给出任何确认。不提供可靠支付。
(2)传输控制协议TCP(transmission control protocol)
提供可靠的、面向连接的服务。在传送数据之前必须先建立连接,数据传送后要释放连接。不提供广播或多播服务。
按OSI术语,两个对等运输实体在通信时传送的数据单位叫作运输协议数据单元TPDU(transport protocol data unit)。但在TCP/IP体系中,则根据所使用的协议是TCP或UDP,分别称之为TCP报文段或UDP用户数据报。
3.运输层的端口
Ⅰ、运输层的复用——应用层所有的应用进程都可以通过运输层再传到IP层
运输层的分用——运输层从IP层收到数据后必须交付给指明的应用进程
Ⅱ、为什么要在运输层使用协议端口号(protocol port number,或端口)?
给应用层的每个应用进程赋予一个非常明确的标志很重要。在单个计算机中的进程是用进程标识符来标志的。但在因特网环境下,就不行了,因为在因特网上使用的计算机的操作系统种类很多,而不同的操作系统又使用不同格式的进程标志符。为了使运行不同操作系统的计算机的应用进程能够互相通信,就必须用统一的方法(而这种方法必须与特定操作系统无关)对TCP/IP体系的应用进程进行标志。
但是,把一个特定机器上运行的特定进程指明为因特网上通信最后的终点还是不可行的。这是因为进程的创建和撤销都是动态的,通信的一方几乎无法识别对方机器上的进程。另外,我们往往需要利用目的主机提供的功能来识别终点,而不需要知道具体实现这个功能的进程是哪一个。
解决这个问题的方法就是在运输层使用协议端口号。虽然通信的终点是应用进程,但我们只要把要传送的报文交到目的主机的某一个合适的目的端口,剩下的工作(即最后交付给目的进程)就由TCP来完成。
Ⅲ、端口认知
这种在协议栈层间抽象的协议端口是软件端口,软件端口是应用层的各种协议进程与运输实体进行层间交互的一种地址。
路由器或交换机上的硬件端口是不同硬件设备进行交互的接口。
Ⅳ、端口号
只具有本地意义,只是为了标志本计算机应用层中的各个进程和运输层交互时的层间接口。在因特网不同计算机中,相同的端口号是没有关联的。
两计算机中的进程通信时,不仅需要知道对方的IP地址(为了找到对方的计算机),还要知道对方的端口号(为了找到对方计算机中的应用进程)。因特网上的计算机通信采用客户—服务器方式,于是运输层的端口号可分为:
(1)服务器端使用的端口号
①熟知端口号(well-known port number)或系统端口号
IANA把这些端口号指派给了TCP/IP最重要的一些应用程序,让所有的客户都知道。当一种新的应用程序出现后,IANA必须为它指派一个熟知端口,否则因特网上的其他应用进程就无法和它进行通信。
②登记端口号
是为没有熟知端口号的应用程序使用的,使用这类端口号必须在IANA按照规定的手续登记,以防止重复。
(2)客户端使用的端口号(短暂端口号)
仅在客户进程运行时才动态选择,留给客户进程选择时暂时使用。当服务器进程收到客户进程的报文时,就知道了客户进程所使用的端口号,因而可以把数据发送给客户进程。通信结束后,刚才已使用过的客户端口号就不复存在。这个端口号就可以供其他客户进程以后使用。
二、用户数据报协议UDP
1.UDP概述
只在IP的数据服务之上增加了很少一点功能,这就是复用和分用、差错检测。
主要特点:(1)无连接的。发送数据之前不需要建立连接(发送完可释放)(2)使用尽最大努力交付,即不保证可靠交付,主机不需要维持复杂的连接状态表。(3)面向报文的。UDP一次交付一个完整的报文,因此应用程序必须选择合适大小的报文。若报文太长,UDP把它交给IP层后,IP层在传送时可能要进行分片,这会降低IP层的效率。反之,若报文太短,UDP把它交给IP层后,会使IP层的首部的相对长度太大,这也降低了IP层的效率。
(4)没有堵塞控制
网络出现的堵塞不会使源主机的发送速率降低,这对某些实时应用很重要,比如实时视频会议要求源主机以恒定的速率发送数据,并且允许在网络发生堵塞时丢失一些数据,但却不允许数据有太大的时延。
但当很多源主机同时向网络发送高速率的实时视频流时,网络就有可能发生堵塞,结果大家都无法正常接收。还有些实时应用需要对它的不可靠传输进行适当的改造,以减少数据的丢失。
(5)支持一对一、一对多、多对一、多对多的交互通信
(6)首部开销小,只有8个字节
2.UDP的首部格式
用户数据报UDP有两个字段:数据字段和首部字段。首部字段很简单,只有8个字节,由四个字段组成,每个字段的长度都是两个字节。各字段:
(1)源端口:源端口号,在需要对方回信时选用,不需要时可用全0。
(2)目的端口:目的端口号,这在终点交付报文时必须要使用到。
(3)长度:UDP用户数据报的长度,其最小值是8(只有首部)。
(4)检验和:检测UDP用户数据报在传输中是否有差错,有错就丢弃。
当运输层从IP层收到UDP数据报时,就根据首部中的目的端口,把UDP数据报通过相应的端口,上交最后的终点——应用进程。下图是UDP基于端口的分用的示意图。
如果接收方UDP发现收到的报文中的目的端口号不正确(即不存在对应于该端口号的应用进程),就丢弃该报文,并由ICMP发送“端口不可达”差错报文给发送方。我们在上一章4.4.2节讨论traceroute时,就是让发送的UDP用户数据报故意使用一个非法的UDP端口,结果ICMP就返回“端口不可达”差错报文,因而达到了测试的目的。
检验和的计算方法:
(1)伪首部——12字节,它不是UDP用户数据报真正的首部,只是用于计算检验和而临时添加的,它既不向下传送也不向上递交。
(2)和IP数据报首部检验和的方法的不同——IP数据报的检验和只检验IP数据报的首部,而UDP的检验和是把首部和数据部分一起都检验。
(3)发送方——先把全零放入检验和字段,再把伪首部以及UDP用户数据报看成是由许多16位的字串接起来。若UDP用户数据报的数据部分不是偶数个字节,则要填入一个全零字节(但此字节不发送)。然后按二进制反码计算出这些16位字的和。将此和的二进制反码写入检验和字段后,就发送这样的UDP用户数据报。
(4)接收方——把收到的UDP用户数据报连同伪首部(以及可能的填充全零字节)一起,按二进制反码求这些16位字的和。当无差错时结果应全1。否则就表明有差错实现,接收方就丢弃这个UDP用户数据报(也可以上交给应用层,但附上出现差错的警告)。
(5)评价——检错能力不强,但简单、处理起来较快。
伪首部的第3字段全是0,第4字段是IP首部中的协议字段的值。以前已讲过,对于UDP,此协议字段值为17。第5字段是UDP用户数据报的长度。因此,这样的检验和,既检查了UDP用户数据报的源端口和目的端口号以及UDP用户数据报的数据部分,又检查了IP数据报的源IP地址和目的地址。
三、传输控制协议TCP概述
1.TCP最重要的特点
(1)是面向连接的运输层协议:传送数据完毕后,必须释放已建立的TCP连接。
(2)每一条TCP连接只能有两个端点(endpoint),每一条TCP连接只能是点对点的。
(3)提供可靠交付的服务——无差错、不丢失、不重复、且按序到达。
(4)全双工通信——TCP允许通信双方的应用进程在任何时候都能发送数据,TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。
(5)面向字节流
“流”是指流入到进程或从进程流出的字节序列。面向字节流的含义是:虽然应用程序和TCP的交互是一次一个数据块(大小不等),但TCP把应用程序交下来的数据看成仅仅是一连串的无结构的字节流。TCP并不知道所传送的字节流的含义,它不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系(例如,发送方应用程序交给发送方的TCP共10个数据块,但接收方的TCP可能只用了4个数据块就把收到的字节流交付给了上层的应用程序)。但接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样。当然,接收方的应用程序必须有能力识别收到的字节流,把它还原成有意义的应用层数据。
解释上图:TCP连接是一条虚连接而不是一条真正的物理连接。TCP报文段先要传送到IP层,加上IP首部后,再传送到数据链路层。再加上数据链路层的首部和尾部后,才离开主机发送到物理链路。
TCP和UDP在发送报文时采用的方式完全不同。TCP对应用程序一次把多长的报文发送到TCP的缓存中是不关心的。TCP根据对方给出的窗口值和当前网络拥塞的程度来决定一个报文段应包含多少个字节(UDP发送的报文长度是应用进程给出的)。如果应用进程传送到TCP缓存的数据块太长,TCP就可以把它划分短一些再传送。如果应用进程一次只发来一个字节,TCP也可以等待积累有足够多的字节后再构成报文段发送出去。
2.TCP的连接
TCP把连接作为最基本的抽象,TCP的许多特性都与TCP是面向连接的这个基本特性有关。
每一条TCP连接有两个端点,它不是主机、不是主机的IP地址、不是应用进程、不是运输层的协议端口,而是套接字(是端口号拼接到IP地址即构成了套接字)。套接字socket=(IP地址:端口号)
每一条TCP连接唯一地被通信两端的两个端点(即两个套接字)所确定。即:
TCP连接::={socket1,socket2}={(IP1:port1),(IP2:port2)}
TCP连接就是由协议软件所提供的一种抽象,是应用进程之间建立的。TCP连接的端点是套接字,即(IP地址:端口号)。同一个IP地址可以有很多个不同的TCP连接,而同一个端口号也可以出现在多个不同的TCP连接中。
注意:socket有很多意思。
四、可靠传输的工作原理
TCP发送的报文段是交给IP层传送的,但IP层只能提供尽最大努力服务,也就是说,TCP下面的网络所提供的是不可靠传输。TCP必须采用适当的措施才能使得两个运输层之间的通信变得可靠。
理想传输条件有:①传输信道不产生差错。②不管发送方以多快的速度发送数据,接收方总是来得及处理收到的数据。
在这样的理想传输条件下,不需要采取任何措施就能实现可靠传输。达不到时,我们可以使用可靠传输协议。当出现差错时让发送方重传出现差错的数据,同时在接收方来不及处理收到的数据时,及时告诉发送方适当降低发送数据的速度。
1.停止等待协议
因为这里是讨论可靠传输的原理,因此把传送的数据单元都称为分组,而不考虑数据是在哪一层次上传送的。“停止等待”就是每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。
Ⅰ、无差错情况
A在收到了对M1的确认后,就再发送给下一个分组M2。
Ⅱ、出现差错
B接收M1时检测出了差错,就丢弃M1,其他什么也不做(不通知A收到有差错的分组),也可能是M1在传输过程中丢失了,这时B当然什么都不知道。在这两种情况下,B都不会发送任何信息。可靠传输协议是这样设计的:A只要超过了一段时间仍然没有收到确认,就认为刚刚发送的分组丢失了,因而重传前面发送过的分组。这就叫做超时重传。
要实现超时重传,就要在每发送完一个分组设置一个超时计时器。如果在超时计时器到期之前收到了对方的确认,就撤销已设置的超时计时器。在a图中,A为每一个已发送的分组都设置了一个超时计时器,但A只要在超时计时器到期之前收到了相应的确认,就撤销该超时计时器。
注意:①A在发送完一个分组,必须暂时保留已发送的分组的副本(为发生超时重传时使用)。只有在收到相应的确认后才能清除暂时保留的分组副本。
②分组和确认分组都必须进行编号。这样才能明确是哪一个发送出去的分组收到了确认,而哪一个分组还没有收到确认。
③超时计时器设置的重传时间应当比数据在分组传输的平均往返时间更长一些。如果重传时间设定长了,通信效率就低;如果短了,产生不必要的重传,浪费了网络资源。设定准确的重传时间是复杂的,因为已发送出的分组到底会经过哪些网络,以及时延,都是不确定因素。
Ⅲ、确认丢失和确认迟到
图a:B收到重传分组M1时,采取两行动,一是丢弃这个重复的分组M1,不向上层支付;二是向A发送确认,不能认为已经发送过确认就不再发送,因为A之所以重传M1就表示A没有收到对M1的确认。
图b:确认迟到了,收到就丢弃。如果A不断重传分组但总是收不到确认,说明通信线路太差,不能进行通信。
使用上述的确认和重传机制,我们就可以在不可靠的传输网络上实现可靠的通信。像上述的这种可靠传输协议常称为自动重传请求ARQ(automatic repeat reQuest),意思是重传的请求是自动进行的。接收方不需要请求发送方重传某个出错的分组。
Ⅳ、信道利用率
停止等待协议的优点是简单,但缺点是信道利用率太低。
假定A发送分组需要的时间是Td(=分组长度/数据率);分组正确到达B后,B处理分组的时间可以忽略不计,同时立即发回确认;B发送确认分组需要时间Ta。如果A处理确认分组的时间也可以忽略不计,那么A在经过时间(Td+RTT+Ta)后就可以再发送下一个分组,这里的RTT是往返时间。因为仅仅是在时间Td内才用来送有用的数据(包括分组的首部),因此信道的利用率U可以用下式计算:
为了提高传输效率,发送方可以不使用低效率的停止等待协议,而是采用流水线传输。看下图,它就是发送方可连续发送多个分组,不必每发完一个分组就停下来等待对方的确认。这样可使信道上一直有数据不间断地在传送。显然,这样可获得很高的信道利用率。
当使用流水线传输时,就要使用下面介绍的连续ARQ协议和滑动窗口协议(5.6节讨论)。
2.连续ARQ协议
图a表示发送方维持的发送窗口,它的意义是:位于发送窗口内的5个分组都可以连续发送出去,而不需要等待对方的确认。这样提高了信道利用率。
根据ARQ协议规定,发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置。图b表示发送方收到了对第一个分组的确认,于是把发送窗口向前移动一个分组的位置。如果原来已经发送了前5个分组,那么现在就可以发送窗口内的第6个分组了。
接收方一般都是采用累积确认的方式,即在收到几个分组后,对按序到达的最后一个分组发送确认。这样就表示:到这个分组为止的所有分组都已正确收到了。
累积确认优点:容易实现,及时确认丢失也不必重传。缺点:不能向发送方反映出接收方已经正确收到的所有分组的信息。
例如,如果发送方发送了前5个分组,而中间的第3个分组丢失了。这时接收方只能对前两个分组发送确认。发送方无法知道后面三个分组的下落,而只好把后面的三个分组都再重传一次。这就叫作Go-back-N(回退N),表示需要再退回来重传已发送过的N个分组。可见,当通信线路质量不好时,连续ARQ协议会带来负面的影响。
五、TCP报文段的首部格式
TCP虽然是面向字节流的,但TCP传送的数据单元却是报文段。一个TCP报文段分为首部和数据两部分,而TCP的全部功能都体现在它首部中各字段的作用。因此,弄清首部各字段作用才能弄清它的工作原理。
前20字节固定,后4N(N是整数)字节是根据需要而增加的选项。
(1)源端口和目的端口:TCP的分用是通过端口实现的。
(2)序号
序号范围[0,2^32-1],序号增加到最大值时,下一个序号就又回到0。TCP是面向字节流的,在一个TCP连接中传送的字节流中的每一个字节都按顺序编号,整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段(也叫作报文段序号)值则指的是本报文段所发送的数据的第一个字节的序号。
(3)确认号:是期望收到对方下一个报文段的第一个数据字节的序号。若确认号=N,则表明:到序号N-1为止的所有数据都已正确收到。
(5)数据偏移:占4位,指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。这个字段实际上指出TCP报文段的首部长度。(首部中还有长度不确定的选项字段)
(6)保留:占6位,保留为今后用,但目前设置为0。
(7)紧急URG
当URG置1时,发送应用进程就告诉发送方的TCP有紧急数据要传送。于是发送方TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据,这时要与首部中紧急指针(urgent pointer)字段配合使用。
(8)确认ACK(ACKnowlegment)
仅当ACK置1时,确认号字段才有效。为0时无效。TCP规定,在连接建立后所有传送的报文段都必须把ACK置1。
(9)推送PSH(push)
当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下,TCP就可以使用推送(push)操作。这时,发送方TCP把PSH置1,并立即创建一个报文段发送出去。接收方TCP收到PSH=1的报文段,就尽快地交付给接收应用进程,而不再等到整个缓存都填满了后再向上交付。得少用。
(10)复位RST(ReSeT)
为1时表明TCP连接中出现严重差错(如主机崩溃),必须释放连接,然后再重新建立运输连接。RST置1还用来拒绝一个非法的报文段或拒绝打开一个连接。也成为重建位或重置位。
(11)同步SYN(SYNchronization)
在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使SYN=1和ACK=1。因此,SYN置1就表示这是一个连接请求或连接接受报文。
(12)终止FIN(FINis)
用来释放一个连接。为1时表明此报文段的发送方的数据已发送完毕,并要求释放运输连接。
(13)窗口
窗口值是[0,2^16-1]之间的整数。明确指出了现在允许对方发送的数据量,窗口值作为接收方让发送方设置其发送窗口的依据。有这个限制是因为接收方的数据缓存空间是有限的。
(14)检验和
检验和字段检验的范围包括首部和数据这两部分。和UDP用户数据报一样,在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。伪首部的格式与UDP用户数据报的伪首部一样。但应把伪首部第4个字段中的17改为6(TCP的协议号是6),把第5字段中的UDP长度改为TCP长度。接收方收到此报文段后,仍要加上这个伪首部来计算检验和。若使用IPv6,则相应的伪首部也要改变。
(15)紧急指针
仅在URG=1时才有意义,指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据)。当所有紧急数据处理完时,TCP就告诉应用程序恢复到正常操作。即使窗口为零时也可以发送紧急数据。
(16)选项
长度可变,最长可达40字节。没有使用选项时,TCP首部长度是20字节。有以下几种:
①最大报文段长度MSS(maximum segment size)
理解——它是每一个TCP报文段中的数据字段的最大长度。数据字段加上TCP首部才等于整个的TCP报文段。所以MSS并不是整个TCP报文段的最大长度,而是“TCP报文段长度减去TCP首部长度”。
出现缘由——并不是考虑接收方的接收缓存可能放不下TCP报文段中的数据。实际上,MSS与接收窗口值没有关系。我们知道,TCP报文段的数据部分,至少加上40字节的首部(TCP首部20字节和IP首部20字节,这里都还没有考虑首部中的选项部分),才能组装成一个IP数据报。MISS长度小时,网络的利用率低。长度大时,IP层传输时就有可能要分解成多个短数据报片,在终点要把收到的各个短数据报片装配成原来的TCP报文段。当传输出错时要重传,这些使开销增大。
因此,MSS应尽可能大些,只要在IP层传输时不需要再分片就行。而IP数据报所经历的路径是动态变化的,因此这条路径不用分片下条路径可能要分片,于是最佳MSS难确定。在连接建立过程中,双方都把自己能够支持的MSS写入这一字段,以后就按照这个数值传送数据,两个传送方向可以有不同的MSS值。若主机未填写这一项,则MSS的默认值是536字节长。因此,所有在因特网上的主机都应能接受的报文段长度是536+20(固定首部长度)=556字节。
②窗口扩大选项
为了扩大窗口。占3字节,其中有一个字节表示移位值S。新的窗口值等于TCP首部中的窗口数从16增大到(16+S),这相当于把窗口值向左移动S位后获得实际的窗口大小。移位值允许使用的最大值是14,相当于窗口最大值增大到2^(16+14)-1。
窗口扩大选项可以在双方初始建立TCP连接时进行协商。如果连接的某一端实现了窗口扩大,当它不再需要扩大其窗口时,可发送S=0的选项,使窗口大小回到16。
③时间戳选项
占10字节,最主要的字段时间戳字段(4字节)和时间戳回送回答字段(4字节)。功能:一是用来计算往返时间RTT。发送方在发送报文段时把当前时钟的时间值放入时间戳字段,接收方在确认该报文段时把时间戳字段值复制到时间戳回送回答字段。因此,发送方在收到确认报文后,可以准确计算出RTT来。二是处理TCP序号超过2^32的情况,这又称为防止序号绕回PAWS(protect against wrapped sequence nambers),可以使接收方能够把新的报文段和迟到很久的报文段区分开。
④选择确认选项
5.6.3节介绍