资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,*,*,ICMP,不可达差错(需要分片),发生,I C M P,不可达差错的另一种情况是,当路由器收到一份需要分片的数据报,而在,I P,首部又设置了不分片(,D F,)的标志比特。如果某个程序需要判断到达目的端的路途中最小,M T U,是多少,称作路径,M T U,发现机制(,2.9,节),那么这个差错就可以被该程序使用。,这种情况下的,I C M P,不可达差错报文格式如图,11-9,所示。这里的格式与图,6-1 0,不同,因为在第,2,个,32 bit,字中,,1631 bit,可以提供下一站的,M T U,,而不再是,0,。,如果路由器没有提供这种新的,ICMP,差错报文格式,那么下一站的,MTU,就设为,0,。,新版的路由器需求,RFC,Almquist,1993,声明,在发生这种,I C M P,不可达差错时,路由器必须生成这种新格式的报文。,例子,关于分片作者曾经遇到过一个问题,,I C M P,差错试图判断从路由器,n e t b,到主机,s u n,之间的拨号,S L I P,链路的,M T U,。我们知道从,s u n,到,n e t b,的链路的,M T U,:当,S L I P,被安装到主机,s u n,时,这是,S L I P,配置过程中的一部分,加上在,3.9,节中已经通过,n e t s t a t,命令观察过。现在,我们想从另一个方向来判断它的,M T U,(在第,2 5,章,将讨论如何用,S N M P,来判断)。在点到点的链路中,不要求两个方向的,M T U,为相同值。,所采用的技术是在主机,s o l a r i s,上运行,p i n g,程序到主机,b s d i,,增加数据分组长度,直到看见进入的分组被分片为止。如图,11-1 0,所示。,在主机,s u n,上运行,t c p d u m p,,观察,S L I P,链路,看什么时候发生分片。开始没有观察到分片,一切都很正常直到,p i n g,分组的数据长度从,5 0 0,增加到,6 0 0,字节。可以看到接收到的回显请求(仍然没有分片),但不见回显应答。,为了跟踪下去,也在主机,b s d i,上运行,t c p d u m p,,观察它接收和发送的报文。输出如图,11-11,所示。,首先,每行中的标记(,D F,)说明在,I P,首部中设置了不分片比特。这意味着,Solaris 2.2,一般把不分片比特置,1,,作为实现路径,M T U,发现机制的一部分。,第,1,行显示的是回显请求通过路由器,n e t b,到达,s u n,主机,没有进行分片,并设置了,D F,比特,因此我们知道还没有达到,n e t b,的,SLIP MTU,。,接下来,在第,2,行注意到,D F,标志被复制到回显应答报文中。这就带来了问题。回显应答与回显请求报文长度相同(超过,6 0 0,字节),但是,s u n,外出的,S L I P,接口,M T U,为,5 5 2,。因此回显应答需要进行分片,但是,D F,标志比特又被设置了。这样,,s u n,就产生一个,I C M P,不可达差错报文返回给,b s d i,(报文在,b s d i,处被丢弃)。,这就是我们在主机,s o l a r i s,上没有看到任何回显应答的原因。这些应答永远不能通过,s u n,。分组的路径如图,11-1 2,所示。,最后,在图,11-11,中的第,3,行和第,6,行中,,m t u=0,表示主机,s u n,没有在,I C M P,不可达报文中返回出口,M T U,值,如图,11-9,所示(在,2 5.9,节中,将重新回到这个问题,用,S N M P,判断,n e t b,上的,S L I P,接口,M T U,值为,1 5 0 0,)。,用,Traceroute,确定路径,MTU,尽管大多数的系统不支持路径,M T U,发现功能,但可以很容易地修改,t r a c e r o u t e,程序(第,8,章),用它来确定路径,M T U,。要做的是发送分组,并设置“不分片”标志比特。发送的第一个分组的长度正好与出口,M T U,相等,每次收到,I C M P“,不能分片”差错时(在上一节讨论的)就减小分组的长度。如果路由器发送的,I C M P,差错报文是新格式,包含出口的,M T U,,那么就用该,M T U,值来发送,否则就用下一个最小的,M T U,值来发送。正如,RFC 1191 Mogul,andDeering,1990,声明的那样,,M T U,值的个数是有限的,因此在我们的程序中有一些由近似值构成的表,取下一个最小,M T U,值来发送。,首先,我们尝试判断从主机,sun,到主机,slip,的路径,MTU,,知道,SLIP,链路的,MTU,为,2 9 6,。,在这个例子中,路由器,b s d i,没有在,I C M P,差错报文中返回出口,M T U,,因此我们选择另一个,M T U,近似值。,T T L,为,2,的第,1,行输出打印的主机名为,b s d i,,但这是因为它是返回,I C M P,差错报文的路由器。,T T L,为,2,的最后一行正是我们所要找的。,在,b s d i,上修改,I C M P,代码使它返回出口,M T U,值并不困难,如果那样做并再次运行该程序得到如下输出结果:,这时,在找到正确的,M T U,值之前,我们不用逐个尝试,8,个不同的,M T U,值,路由器返回了正确的,M T U,值。,采用,UDP,的路径,MTU,发现,下面对使用,U D P,的应用程序与路径,M T U,发现机制之间的交互作用进行研究。看一看如果应用程序写了一个对于一些中间链路来说太长的数据报时会发生什么情况。,由于我们所使用的支持路径,M T U,发现机制的唯一系统就是,Solaris 2.x,,因此,将采用它作为源站发送一份,6 5 0,字节数据报经,s l i p,。由于,s l i p,主机位于,M T U,为,2 9 6,的,S L I P,链路后,因此,任何长于,2 6 8,字节(,2 9 6,2 0,8,)且“不分片”比特置为,1,的,U D P,数据都会使,b s d i,路由器产生,I C M P“,不能分片”差错报文。图,11-1 3,给出了拓扑结构和,M T U,。,可以用下面的命令行来产生,650,字节,UDP,数据报,每两个,UDP,数据报之间的间隔是,5,秒:,solaris,%sock-u-i-n10-w650-p5 slip discard,图,11-1 4,是,t c p d u m p,的输出结果。在运行这个例子时,将,b s d i,设置成在,I C M P“,不能分片”差错中,不返回下一跳,M T U,信息。,在发送的第一个数据报中将,D F,比特置,1,(第,1,行),其结果是从,b s d i,路由器发回我们可以猜测的结果(第,2,行)。令人不解的是,发送一个,D F,比特置,1,的数据报(第,3,行),其结果是同样的,I C M P,差错(第,4,行)。我们预计这个数据报在发送时应该将,D F,比特置,0,。,第,5,行结果显示,,I P,已经知道了发往该目的地址的数据报不能将,D F,比特置,1,,因此,,I P,进而将数据报在源站主机上进行分片。这与前面的例子中,,I P,发送经过,U D P,的数据报,允许具有较小,M T U,的路由器(在本例中是,b s d i,)对它进行分片的情况不一样。由于,I C M P“,不能分片”报文并没有指出下一跳的,M T U,,因此,看来,I P,猜测,M T U,为,5 7 6,就行了。第一次分片(第,5,行)包含,5 4 4,字节的,U D P,数据、,8,字节,U D P,首部以及,2 0,字节,I P,首部,因此,总,I P,数据报长度是,5 7 2,字节。第,2,次分片(第,6,行)包含剩余的,1 0 6,字节,U D P,数据和,2 0,字节,I P,首部。,不幸的是,第,7,行的下一个数据报将其,D F,比特置,1,,因此,b s d i,将它丢弃并返回,I C M P,差错。这时发生了,I P,定时器超时,通知,I P,查看是不是因为路径,M T U,增大了而将,D F,比特再一次置,1,。我们可以从第,1 9,行和,2 0,行看出这个结果。将第,7,行与,1 9,行进行比较,可以看出,I P,每过,3 0,秒就将,D F,比特置,1,,以查看路径,M T U,是否增大了。,这个,3 0,秒的定时器值看来太短。,R F C 11 9 1,建议其值取,1 0,分钟。可以通过修改,i p _ i r e _ p a t h m t u _ i n t e r v a l,(,E.4,节)参数来改变该值。同时,,Solaris 2.2,无法对单个,U D P,应用或所有,U D P,应用关闭该路径,M T U,发现。只能通过修改,i p _ p a t h _ m t u _ d i s c o v e r y,参数,在系统一级开放或关闭它。正如在这个例子里所能看到的那样,如果允许路径,M T U,发现,那么当,U D P,应用程序写入可能被分片数据报时,该数据报将被丢弃。,s o l a r i s,的,I P,层所假设的最大数据报长度(,5 7 6,字节)是不正确的。在图,11-1 3,中,我们看到,实际的,M T U,值是,2 9 6,字节。这意味着经,s o l a r i s,分片的数据报还将被,b s d i,分片。图,11-1 5,给出了在目的主机(,s l i p,)上所收集到的,t c p d u m p,对于第一个到达数据报的输出结果(图,11-1 4,的第,5,行和第,6,行)。,在本例中,,s o l a r i s,不应该对外出数据报分片,它应该将,D F,比特置,0,,让具有最小,M T U,的路由器来完成分片工作。,现在我们运行同一个例子,只是对路由器,b s d i,进行修改使其在,I C M P“,不能分片”差错中返回下一跳,M T U,。图,11-1 6,给出了,t c p d u m p,输出结果的前,6,行。,UDP,和,ARP,之间的交互作用,使用,U D P,,可以看到,U D P,与,A R P,典型实现之间的有趣的(而常常未被人提及)交互作用。,我们用,s o c k,程序来产生一个包含,8 1 9 2,字节数据的,U D P,数据报。预测这将会在以太网上产生,6,个数据报片(见习题,11.3,)。同时也确保在运行该程序前,,A R P,缓存是清空的,这样,在发送第一个数据报片前必须交换,A R P,请求和应答。,bsdi,%,arp,-a,验证,A R P,高速缓存是空的,bsdi,%sock-u-i-,nl,-w8192 svr4 discard,预计在发送第一个数据报片前会先发送一个,A R P,请求。,I P,还会产生,5,个数据报片,这样就提出了我们必须用,t c p d u m p,来回答的两个问题:在接收到,A R P,回答前,其余数据报片是否已经做好了发送准备?如果是这样,那么在,A R P,等待应答时,它会如何处理发往给定目的的多个报文?图,11-1 7,给出了,t c p d u m p,的输出结果。,在这个输出结果中有一些令人吃惊的结果。首先,在第一个,A R P,应答返回以前,总共产生了,6,个,A R P,请求。我们认为其原因是,I P,很快地产生了,6,个数据报片,而每个数据报片都引发了一个,A R P,请求。,第二,在接收到第一个,A R P,应答时(第,7,行),只发送最后一个数据报片(第,9,行)!看来似乎将前,5,个数据报片全都丢弃了。实际上,这是,A R P,的正常操作。在大多数的实现中,在等待一个,A R P,应答时,只将最后一个报文发送给特定目的主机。,Host Requirements RFC,要求实现中必须防止这种类型的,A R P,洪泛(,ARP flooding,,即以高速率重复发送到同一个,I P,地址的,A R P,请求)。建议最高速率是每秒一次。而这里却在,4.3 ms,内发出了,6,个,ARP,请求。,Host Requirements RFC,规定,,ARP,应该保留至少一个报文,而这个报文必须是最后一个报文。这正是我们在这里所看到的结果。,另一个无法解释的不正常的现象是,,s v r 4,发回,7,个,而不是,6,个,A R P,应答。,最后要指出的是,在最后一个,A R P,应答返回后,继续运行,t c p d u m p,程序,5,分钟,以看看,s v r 4,是否会返回,I C M P“,组装超时”差错。并没有发送,I C M P,差错(我们在图,8-2,中给出了该消息的格式。,c o d e,字段为,1,表示在重新组装数据报时发生了超时)。,在第一个数据报片出现时,,I P,层必须启动一个定时器。这里“第一个”表示给定数据报的第一个到达数据报片,而不是第一个数据报片(数据报片偏移为,0,)。正常的定时器值为,3 0,或,6 0,秒。如果定时器超时而该数据报的所有数据报片未能全部到达,那么将这些数据报片丢弃。如果不这么做,那些永远不会到达的数据报片(正如我们在本例中所看到的那样)迟早会引起接收端缓存满。,这里我们没看到,I C M P,消息的原因有两个。首先,大多数从,B e r k e l e y,派生的实现从不产生该差错!这些实现会设置定时器,也会在定时器溢出时将数据报片丢弃,但是不生成,I C M P,差错。第二,并未接收到包含,U D P,首部的偏移量为,0,的第一个数据报片(这是被,A R P,所丢弃的,5,个报文的第,1,个)。除非接收到第一个数据报片,否则并不要求任何实现产生,I C M P,差错。其原因是因为没有运输层首部,,I C M P,差错的接收者无法区分出是哪个进程所发送的数据报被丢弃。这里假设上层(,T C P,或使用,U D P,的应用程序)最终会超时并重传。,在本节中,我们使用,I P,数据报片来查看,U D P,与,A R P,之间的交互作用。如果发送端迅速发送多个,U D P,数据报,也可以看到这个交互过程。我们选择采用分片的方法,是因为,I P,可以生成报文的速度,比一个用户进程生成多个数据报的速度更快。,尽管本例看来不太可能,但它确实经常发生。,N F S,发送的,U D P,数据报长度超过,8 1 9 2,字节。在以太网上,这些数据报以我们所指出的方式进行分片,如果适当的,A R P,缓存入口发生超时,那么就可以看到这里所显示的现象。,N F S,将超时并重传,但是由于,A R P,的有限队列,第一个,I P,数据报仍可能被丢弃。,最大,UDP,数据报长度,理论上,,I P,数据报的最大长度是,6 5 5 3 5,字节,这是由,I P,首部(图,3-1,),1 6,比特总长度字段所限制的。去除,2 0,字节的,I P,首部和,8,个字节的,U D P,首部,,U D P,数据报中用户数据的最长长度为,6 5 5 0 7,字节。但是,大多数实现所提供的长度比这个最大值小。,我们将遇到两个限制因素。第一,应用程序可能会受到其程序接口的限制。,socket API,提供了一个可供应用程序调用的函数,以设置接收和发送缓存的长度。对于,UDP socket,,这个长度与应用程序可以读写的最大,U D P,数据报的长度直接相关。现在的大部分系统都默认提供了可读写大于,8 1 9 2,字节的,U D P,数据报(使用这个默认值是因为,8 1 9 2,是,N F S,读写用户数据数的默认值)。,第二个限制来自于,T C P/I P,的内核实现。可能存在一些实现特性(或差错),使,I P,数据报长度小于,6 5 5 3 5,字节。,作者使用,s o c k,程序对不同,U D P,数据报长度进行了试验。在,SunOS 4.1.3,下使用环回接口的最大,I P,数据报长度是,3 2 7 6 7,字节。比它大的值都会发生差错。但是从,B S D/3 8 6,到,SunOS 4.1.3,的情况下,,S u n,所能接收到最大,I P,数据报长度为,3 2 7 8 6,字节(即,3 2 7 5 8,字节用户数据)。在,Solaris 2.2,下使用环回接口,最大可收发,I P,数据报长度为,6 5 5 3 5,字节。从,Solaris 2.2,到,AIX 3.2.2,,发送的最大,IP,数据报长度可以是,65535,字节。很显然,这个限制与源端和目的端的实现有关。,我们在,3.2,节中提过,要求主机必须能够接收最短为,5 7 6,字节的,I P,数据报。在许多,U D P,应用程序的设计中,其应用程序数据被限制成,5 1 2,字节或更小,因此比这个限制值小。例如,我们在,1 0.4,节中看到,路径信息协议总是发送每份数据报小于,5 1 2,字节的数据。我们还会在其他,U D P,应用程序如,D N S,(第,1 4,章)、,T F T P,(第,1 5,章)、,B O O T P,(第,1 6,章)以及,S N M P,(第,2 5,章)中遇到这个限制。,由于,I P,能够发送或接收特定长度的数据报并不意味着接收应用程序可以读取该长度的数据。因此,,U D P,编程接口允许应用程序指定每次返回的最大字节数。如果接收到的数据报长度大于应用程序所能处理的长度,那么会发生什么情况呢?,不幸的是,该问题的答案取决于编程接口和实现。,典型的,B e r k e l e y,版,socket API,对数据报进行截断,并丢弃任何多余的数据。应用程序何时能够知道,则与版本有关(,4.3BSD Reno,及其后的版本可以通知应用程序数据报被截断)。,S V R 4,下的,socket API(,包括,Solaris 2.x),并不截断数据报。超出部分数据在后面的读取中返回。它也不通知应用程序从单个,UDP,数据报中多次进行读取操作。,TLI API,不丢弃数据。相反,它返回一个标志表明可以获得更多的数据,而应用程序后面的读操作将返回数据报的其余部分。,在讨论,T C P,时,我们发现它为应用程序提供连续的字节流,而没有任何信息边界。,T C P,以应用程序读操作时所要求的长度来传送数据,因此,在这个接口下,不会发生数据丢失。,ICMP,源站抑制差错,我们同样也可以使用,U D P,产生,I C M P“,源站抑制,(source quench)”,差错。当一个系统(路由器或主机)接收数据报的速度比其处理速度快时,可能产生这个差错。注意限定词“可能”。即使一个系统已经没有缓存并丢弃数据报,也不要求它一定要发送源站抑制报文。,图,11-1 8,给出了,I C M P,源站抑制差错报文的格式。有一个很好的方案可以在我们的测试网络里产生该差错报文。可以从,b s d i,通过必须经过拨号,S L I P,链路的以太网,将数据报发送给路由器,s u n,。由于,S L I P,链路的速度大约只有以太网的千分之一,因此,我们很容易就可以使其缓存用完。下面的命令行从主机,b s d i,通过路由器,s u n,发送,1 0 0,个,1 0 2 4,字节长数据报给,s o l a r i s,。我们将数据报发送给标准的丢弃服务,这样,这些数据报将被忽略:,bsdi,%sock-u-i-w1024-n100,solaris,discard,图,11-1 9,给出了与此命令行相对应的,t c p d u m p,输出结果,在这个输出结果中,删除了很多行,这只是一个模型。接收前,2 6,个数据报时未发生差错;我们只给出了第一个数据报的结果。然而,从第,2 7,个数据报开始,每发送一份数据报,就会接收到一份源站抑制差错报文。总共有,26+742,),=174,行输出结果。,从,2.1 0,节的并行线吞吐率计算结果可以知道,以,9600,b/s,速率传送,1 0 2 4,字节数据报只需要,1,秒时间(由于从,s u n,到,n e t b,的,S L I P,链路的,M T U,为,5 5 2,字节,因此在我们的例子中,,20+8+1 0 2 4,字节数据报将进行分片,因此,其时间会稍长一些)。但是我们可以从图,11-1 9,的时间中看出,,s u n,路由器在不到,1,秒时间内就处理完所有的,1 0 0,个数据报,而这时,第一份数据报还未通过,S L I P,链路。因此我们用完其缓存就不足不奇了。,尽管,RFC 1009 Braden and,Postel,1987,要求路由器在没有缓存时产生源站抑制差错报文,但是新的,Router Requirements RFC,Almquist,1993,对此作了修改,提出路由器不应该产生源站抑制差错报文。由于源站抑制要消耗网络带宽,且对于拥塞来说是一种无效而不公平的调整,因此现在人们对于源站抑制差错的态度是不支持的。,在本例中,还需要指出的是,,s o c k,程序要么没有接收到源站抑制差错报文,要么接收到却将它们忽略了。结果是如果采用,U D P,协议,那么,B S D,实现通常忽略其接收到的源站抑制报文(正如我们在,2 1.1 0,节所讨论的那样,,T C P,接受源站抑制差错报文,并将放慢在该连接上的数据传输速度)。其部分原因在于,在接收到源站抑制差错报文时,导致源站抑制的进程可能已经中止了。实际上,如果使用,Unix,的,t i m e,程序来测定,s o c k,程序所运行的时间,其结果是它只运行了大约,0.5,秒时间。但是从图,11-1 9,中可以看到,在发送第一份数据报过后,0.7 1,秒才接收到一些源站抑制,而此时该进程已经中止。其原因是我们的程序写入了,1 0 0,个数据报然后中止了。但是所有的,1 0 0,个数据报都已发送出去,有一些数据报在输出队列中。,这个例子重申了,U D P,是一个非可靠的协议,它说明了端到端的流量控制。尽管,s o c k,程序成功地将,1 0 0,个数据报写入其网络,但只有,2 6,个数据报真正发送到了目的端。其他,7 4,个数据报可能被中间路由器丢弃。除非在应用程序中建立一些应答机制,否则发送端并不知道接收端是否收到了这些数据。,UDP,服务器的设计,使用,U D P,的一些蕴含对于设计和实现服务器会产生影响。通常,客户端的设计和实现比服务器端的要容易一些,这就是我们为什么要讨论服务器的设计,而不是讨论客户端的设计的原因。典型的服务器与操作系统进行交互作用,而且大多数需要同时处理多个客户。,通常一个客户启动后直接与单个服务器通信,然后就结束了。而对于服务器来说,它启动后处于休眠状态,等待客户请求的到来。对于,U D P,来说,当客户数据报到达时,服务器苏醒过来,数据报中可能包含来自客户的某种形式的请求消息。,在这里我们所感兴趣的并不是客户和服务器的编程方面(,Stevens 1990,对这些方面的细节进行了讨论),而是,U D P,那些影响使用该协议的服务器的设计和实现方面的协议特性(我们在,1 8.11,节中对,T C P,服务器的设计进行了描述)。尽管我们所描述的一些特性取决于所使用,U D P,的实现,但对于大多数实现来说,这些特性是公共的。,客户,IP,地址及端口号,来自客户的是,U D P,数据报。,I P,首部包含源端和目的端,I P,地址,,U D P,首部包含了源端和目的端的,U D P,端口号。当一个应用程序接收到,U D P,数据报时,操作系统必须告诉它是谁发送了这份消息,即源,I P,地址和端口号。,这个特性允许一个交互,U D P,服务器对多个客户进行处理。给每个发送请求的客户发回应答。,目的,IP,地址,一些应用程序需要知道数据报是发送给谁的,即目的,I P,地址。例如,,Host Requirements R F C,规定,,T F T P,服务器必须忽略接收到的发往广播地址的数据报(我们分别在第,1 2,章和第,1 5,章对广播和,T F T P,进行描述)。,这要求操作系统从接收到的,U D P,数据报中将目的,I P,地址交给应用程序。不幸的是,并非所有的实现都提供这个功能。,socket API,以,I P _ R E C V D S TADDR socket,选项提供了这个功能。对于本文中使用的系统,只有,B S D/3 8 6,、,4.4 B S D,和,AIX 3.2.2,支持该选项。,S V R 4,、,SunOS 4.x,和,Solaris 2.x,都不支持该选项。,UDP,输入队列,我们在,1.8,节中说过,大多数,U D P,服务器是交互服务器。这意味着,单个服务器进程对单个,U D P,端口上(服务器上的名知端口)的所有客户请求进行处理。,通常程序所使用的每个,U D P,端口都与一个有限大小的输入队列相联系。这意味着,来自不同客户的差不多同时到达的请求将由,U D P,自动排队。接收到的,U D P,数据报以其接收顺序交给应用程序(在应用程序要求交送下一个数据报时)。,然而,排队溢出造成内核中的,U D P,模块丢弃数据报的可能性是存在的。可以进行以下试验。我们在作为,U D P,服务器的,b s d i,主机上运行,s o c k,程序:,bsdi,%sock-s-u-v-E-R256-P30 6666,from 140.252.13.33,to 140.252.13.63:1111111111,从,s u n,发送到广播地址,from 140.252.13.34,to 140.252.13.35:4444444444444,从,s v r 4,发送到单播地址,我们指明以下标志:,-s,表示作为服务器运行,,-u,表示,U D P,,,-v,表示打印客户的,I P,地址,,-E,表示打印目的,I P,地址(该系统支持这个功能)。另外,我们将这个端口的,U D P,接收缓存设置为,2 5 6,字节(,-R,),其每次应用程序读取的大小也是这个数(,-r,)。标志,-P 3 0,表示创建,U D P,端口后,先暂停,3 0,秒后再读取第一个数据报。这样,我们就有时间在另两台主机上启动客户程序,发送一些数据报,以查看接收队列是如何工作的。,服务器一开始工作,处于其,3 0,秒的暂停时间内,我们就在,s u n,主机上启动一个客户,并发送三个数据报:,sun%sock-u-v 140.252.13.63 6666,到以太网广播地址,connected on 140.252.13.33.1252 to 140.252.13.63.6666,1 1 1 1 1 1 1 1 1 1 1 1,字节的数据(新行),2 2 2 2 2 2 2 2 2 1 0,字节的数据(新行),3 3 3 3 3 3 3 3 3 3 3 1 2,字节的数据(新行),目的地址是广播地址(,1 4 0.2 5 2.1 3.6 3,)。我们同时也在主机,s v r 4,上启动第,2,个客户,并发送另外三个数据报:,svr4%sock-u-v,bsdi,6666,connected on 0.0.0.0.1042 to 140.252.13.35.6666,4 4 4 4 4 4 4 4 4 4 4 4 4 1 4,字节的数据(新行),5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 1 6,字节的数据(新行),6 6 6 6 6 6 6 6 9,字节的数据(新行),首先,我们早些时候在,b s d i,上所看到的结果表明,应用程序只接收到,2,个数据报:来自,s u n,的第一个全,1,报文,和来自,s v r 4,的第一个全,4,报文。其他,4,个数据报看来全被丢弃。,图,11-2 0,给出的,t c p d u m p,输出结果表明,所有,6,个数据报都发送给了目的主机。两个客户的数据报以交替顺序键入:第一个来自,s u n,,然后是来自,s v r 4,的,以此类推。同时也可以看出,全部,6,个数据报大约在,1 2,秒内发送完毕,也就是在服务器休眠的,3 0,秒内完成的。,我们还可以看到,服务器的,-E,选项使其可以知道每个数据报的目的,I P,地址。如果需要,它可以选择如何处理其接收到的第一个数据报,这个数据报的地址是广播地址。,我们可以从本例中看到以下几个要点。首先,应用程序并不知道其输入队列何时溢出。只是由,U D P,对超出数据报进行丢弃处理。同时,从,t c p d u m p,输出结果,我们看到,没有发回任何信息告诉客户其数据报被丢弃。这里不存在像,I C M P,源站抑制这样发回发送端的消息。最后,看来,U D P,输出队列是,F I F O,(先进先出)的,而我们在,11.9,节中所看到的,A R P,输入却是,限制本地,IP,地址,大多数,U D P,服务器在创建,U D P,端点时都使其本地,I P,地址具有通配符,(w i l d c a r d),的特点。这就表明进入的,U D P,数据报如果其目的地为服务器端口,那么在任何本地接口均可接收到它。例如,我们以端口号,7 7 7,启动一个,U D P,服务器:,sun%sock-u-s 7777,然后,用,n e t s t a t,命令观察端点的状态:,sun%,netstat,-a-n-f,inet,Active Internet connections(including servers),Proto,Recv,-Q Send-Q Local Address Foreign Address (state),udp,0 0 *.7777 *.*,这里,我们删除了许多行,只保留了其中感兴趣的东西。,-a,选项表示报告所有网络端点的状态。,-n,选项表示以点数格式打印,I P,地址而不用,D N S,把地址转换成名字,打印数字端口号而不是服务名称。,-f,inet,选项表示只报告,T C P,和,U D P,端点。,本地地址以*,.7 7 7 7,格式打印,星号表示任何本地,I P,地址。,当服务器创建端点时,它可以把其中一个主机本地,I P,地址包括广播地址指定为端点的本地,I P,地址。只有当目的,I P,地址与指定的地址相匹配时,进入的,U D P,数据报才能被送到这个端点。用我们的,s o c k,程序,如果在端口号之前指定一个,IP,地址,那么该,IP,地址就成为该端点的本地,IP,地址。例如:,sun%sock-u-s 140.252.1.29 7777,就限制服务器在,S L I P,接口,(1 4 0.2 5 2.1.2 9),处接收数据报。,n e t s t a t,输出结果显示如下:,Proto,Recv,-Q Send-Q Local Address Foreign Address (state),udp,0 0 140.252.1.29.7777 *.*,如果我们试图在以太网上的主机,b s d i,以地址,1 4 0.2 5 2.1 3.3 5,向该服务器发送一份数据报,那么将返回一个,I C M P,端口不可达差错。服务器永远看不到这份数据报。这种情形如图,11-2 1,所示。,有可能在相同的端口上启动不同的服务器,每个服务器具有不同的本地,I P,地址。但是,一般必须告诉系统应用程序重用相同的端口号没有问题。,使用,sockets API,时,必须指定,S O _ R E U S E A D D,Rs,o c k e t,选项。在,s o c k,程序中是通过,-A,选项来完成的。,除了第一个以外,其他的服务器都必须以,-A,选项启动,告诉系统可以重用同一个端口号。,5,个服务器的,n e t s t a t,输出结果如下所示:,在这种情况下,到达服务器的数据报中,只有带星号的本地,I P,地址,其目的地址为,1 4 0.2 5 2.1.2 5 5,,因为其他,4,个服务器占用了其他所有可能的,I P,地址。,如果存在一个含星号的,I P,地址,那么就隐含了一种优先级关系。如果为端点指定了特定,I P,地址,那么在匹配目的地址时始终优先匹配该,I P,地址。只有在匹配不成功时才使用含星号的端点。,限制远端,IP,地址,在前面所有的,n e t s t a t,输出结果中,远端,I P,地址和远端端口号都显示为*,.*,,其意思是该端点将接受来自任何,I P,地址和任何端口号的,U D P,数据报。大多数系统允许,U D P,端点对远端地址进行限制。,这说明端点将只能接收特定,I P,地址和端口号的,U D P,数据报。,s o c k,程序用,-f,选项来指定远端,I P,地址和端口号:,sun%sock-u-s-f 140.252.13.35.4444 5555,这样就设置了远端,I P,地址,1 4 0.2 5 2.1 3.3 5,(即主机,b s d i,)和远端端口号,4444,。服务器的有名端口号为,5 5 5 5,。如果运行,n e t s t a t,命令,我们发现本地,I P,地址也被设置了,尽管我们没有指定。,Proto,Recv,-Q Send-Q Local Address Foreign Address (state),udp,0 0 140.252.13.33.5555 140.252.13.35.4444,这是在伯克利派生系统中指定远端,I P,地址和端口号带来的副作用:如果在指定远端地址时没有选择本地地址,那么将自动选择本地地址。它的值就成为选择到达远端,I P,地址路由时将选择的接口,I P,地址。事实上,在这个例子中,,s u n,在以太网上的,I P,地址与远端地址,1 4 0.2 5 2.1 3.3 3,相连。,图,11-2 2,总结了,U D P,服务器本身可以创建的三类地址绑定。,在所有情况下,,l p o r t,指的是服务器有名端口号,,l o c a l I P,必须是本地接口的,I P,地址。表中这三行的排序是,U D P,模块在判断用哪个端点接收数据报时所采用的顺序。最为确定的地址(第一行)首先被匹配,最不确定的地址(最后一行,I P,地址带有两个星号)最后进行匹配。,每个端口有多个接收者,尽管在,R F C,中没有指明,但大多数的系统在某一时刻只允许一个程序端点与某个本地,I P,地址及,U D P,端口号相关联。当目的地为该,I P,地址及端口号的,U D P,数据报到达主机时,就复制一份传给该端点。端点的,I P,地址可以含星号,正如我们前面讨论的那样。,例如,在,SunOS 4.1.3,中,我们启动一个端口号为,9 9 9 9,的服务器,本地,I P,地址含有星号:,sun%sock-u-s 9999,接着,如果启动另一个具有相同本地地址和端口号的服务器,那么它将不运行,尽管我们指定了,-A,选项:,sun%sock-u-s 9999,我们预计它会失败,cant bind local address:Address already in use,sun%sock-u-s-A 9999,因此,这次尝试,-A,参数,cant bind local address:Address already in use,在一个支持多播的系统上(第,1 2,章),这种情况将发生变化。多个端点可以使用同一个,I P,地址和,U D P,端口号,尽管应用程序通常必须告诉,A P I,是可行的(如,用,-A,标志来指明,S O _ R E U S E A D D,Rs,o c k e t,选项)。,4.4 B S D,支持多播传送,需要应用程序设置一个不同的,s o c k e t,选项(,S O _ R E U S E P O R T,)以允许多个端点共享同一个端口。另外,每个端点必须指定这个选项,包括使用该端口的第一个端点。,当,U D P,数据报到达的目的,I P,地址为广播地址或多播地址,而且在目的,I
展开阅读全文