文档库 最新最全的文档下载
当前位置:文档库 › TCP-IP技术大全11

TCP-IP技术大全11

第11章UDP :用户数据报协议

11.1 引言

U D P 是一个简单的面向数据报的运输层协议:进程的每个输出操作都正好产生一个U D P 数据报,并组装成一份待发送的I P 数据报。

这与面向流字符的协议不同,如T C P ,应用

程序产生的全体数据与真正发送的单个I P 数

据报可能没有什么联系。

U D P 数据报封装成一份I P 数据报的格式

如图11 -1所示。

RFC 768 [Postel 1980] 是U D P 的正式规

范。

U D P 不提供可靠性:它把应用程序传给I P 层的数据发送出去,但是并不保证它们能到达目的地。由于缺乏可靠性,我们似乎觉得要避免使用U D P 而使用一种可靠协议如T C P 。我们在第1 7章讨论完T C P 后将再回到这个话题,看看什么样的应用程序可以使用U D P 。

应用程序必须关心I P 数据报的长度。如果它超过网络的M T U (2 .8节),那么就要对I P 数据报进行分片。如果需要,源端到目的端之间的每个网络都要进行分片,并不只是发送端主机连接第一个网络才这样做(我们在2 .9节中已定义了路径M T U 的概念)。在11 .5节中,我们将讨论I P 分片机制。11.2 UDP 首部

U D P 首部的各字段如图11 -2所示。

图11-2 UDP 首部

端口号表示发送进程和接收进程。在图1 -8中,我们画出了T C P 和U D P 用目的端口号来分用来自I P 层的数据的过程。由于I P 层已经把I P 数据报分配给T C P 或U D P (根据I P 首部中协议字段值),因此T C P 端口号由T C P 来查看,而U D P 端口号由U D P 来查看。T C P 端口号与U D P 端口号是相互独立的。

图11-1 UDP 封装

IP 数据报UDP 数据报首部UDP 首部UDP 数据20字节8字节16位源端口号

16位目的端口号16位UDP 长度16位UDP 检验和

数据(如果有)

8字节

尽管相互独立,如果T C P 和U D P 同时提供某种知名服务,两个协议通常选择相同

的端口号。这纯粹是为了使用方便,而不是协议本身的要求。

U D P 长度字段指的是U D P 首部和U D P 数据的字节长度。该字段的最小值为8字节(发送一份0字节的U D P 数据报是O K )。这个U D P 长度是有冗余的。I P 数据报长度指的是数据报全长(图3 -1),因此U D P 数据报长度是全长减去I P 首部的长度(该值在首部长度字段中指定,如图3 -1所示)。

11.3 UDP 检验和

U D P 检验和覆盖U D P 首部和U D P 数据。回想I P 首部的检验和,它只覆盖I P 的首部—并不覆盖I P 数据报中的任何数据。

U D P 和T C P 在首部中都有覆盖它们首部和数据的检验和。U D P 的检验和是可选的,而T C P 的检验和是必需的。

尽管U D P 检验和的基本计算方法与我们在 3 .2节中描述的I P 首部检验和计算方法相类似(16 bit 字的二进制反码和),但是它们之间存在不同的地方。首先,U D P 数据报的长度可以为奇数字节,但是检验和算法是把若干个16 bit 字相加。解决方法是必要时在最后增加填充字节0,这只是为了检验和的计算(也就是说,可能增加的填充字节不被传送)。

其次,U D P 数据报和T C P 段都包含一个1 2字节长的伪首部,它是为了计算检验和而设置的。伪首部包含I P 首部一些字段。其目的是让U D P 两次检查数据是否已经正确到达目的地(例如,I P 没有接受地址不是本主机的数据报,以及I P 没有把应传给另一高层的数据报传给U D P )。U D P 数据报中的伪首部格式如图11 -3所示。

图11-3 UDP 检验和计算过程中使用的各个字段

在该图中,我们特地举了一个奇数长度的数据报例子,因而在计算检验和时需要加上填充字节。注意,U D P 数据报的长度在检验和计算过程中出现两次。

如果检验和的计算结果为0,则存入的值为全1(6 5535),这在二进制反码计算中是等效的。如果传送的检验和为0,说明发送端没有计算检验和。

32位源IP 地址

32位目的IP 地址

08位协议(17)

16位UDP 长度16位目的端口号16位UDP 检验和UDP 首部UDP 伪首部

16位源端口号

16位UDP 长度数据

填充字节(0)

如果发送端没有计算检验和而接收端检测到检验和有差错,那么U D P 数据报就要被悄悄地丢弃。不产生任何差错报文(当I P 层检测到I P 首部检验和有差错时也这样做)。

U D P 检验和是一个端到端的检验和。它由发送端计算,然后由接收端验证。其目的是为了发现U D P 首部和数据在发送端到接收端之间发生的任何改动。

尽管U D P 检验和是可选的,但是它们应该总是在用。在8 0年代,一些计算机产商在默认

条件下关闭U D P 检验和的功能,以提高使用U D P 协议的N F S (Network File System )的速度。在单个局域网中这可能是可以接受的,但是在数据报通过路由器时,通过对链路层数据帧进行循环冗余检验(如以太网或令牌环数据帧)可以检测到大多数的差错,导致传输失败。不管相信与否,路由器中也存在软件和硬件差错,以致于修改数据报中的数据。如果关闭端到端的U D P 检验和功能,那么这些差错在U D P 数据报中就不能被检测出来。另外,一些数据链路层协议(如S L I P )没有任何形式的数据链路检验和。

Host Requirements RFC 声明,U D P 检验和选项在默认条件下是打开的。它还声明,

如果发送端已经计算了检验和,那么接收端必须检验接收到的检验和(如接收到检验

和不为0)。但是,许多系统没有遵守这一点,只是在出口检验和选项被打开时才验证接收到的检验和。

11.3.1 tcpdump 输出

很难知道某个特定系统是否打开了U D P 检验和选项。应用程序通常不可能得到接收到的U D P 首部中的检验和。为了得到这一点,作者在t c p d u m p 程序中增加了一个选项,以打印出接收到的U D P 检验和。如果打印出的值为0,说明发送端没有计算检验和。

测试网络上三个不同系统的输出如图11 -4所示(参见封面二)。运行我们自编的s o c k 程序(附录C

,发送一份包含9个字节数据的U D P 数据报给标准回显服务器。

图11-4 t c p d u m p 输出,观察其他主机是否打开UDP 检验和选项

从这里可以看出,三个系统中有两个打开了U D P 检验和选项。

还要注意的是,在这个简单例子中,送出的数据报与收到的数据报具有相同的检验和值(第3和第4行,第5和第6行)。从图11-3可以看出,两个IP 地址进行了交换,正如两个端口号一样。伪首部和U D P 首部中的其他字段都是相同的,就像数据回显一样。这再次表明U D P 检验和(事实上,TCP/IP 协议簇中所有的检验和)是简单的16 bit 和。它们检测不出交换两个16 bit 的差错。

作者在1 4.2节中在8个域名服务器中各进行了一次D N S 查询。D N S 主要使用U D P ,

结果只有两台服务器打开了UDP 检验和选项。

11.3.2 一些统计结果

文献[Mogul 1992 ]提供了在一个繁忙的N F S 服务器上所发生的不同检验和差错的统计结果,

时间持续了4 0天。统计数字结果如图11 - 5

所示。最后一列是每一行的大概总数,因为以

太网和I P 层还使用其他的协议。例如,不是

所有的以太网数据帧都是I P 数据报,至少以

太网还要使用A R P 协议。不是所有的I P 数据报都是U D P 或T C P 数据,因为I C M P 也用I P 传送数据。

注意,T C P 发生检验和差错的比例与U D P 相比要高得多。这很可能是因为在该系统中的T C P 连接经常是“远程”连接(经过许多路由器和网桥等中间设备),而U D P 一般为本地通信。

从最后一行可以看出,不要完全相信数据链路(如以太网,令牌环等)的 C R C 检验。应该始终打开端到端的检验和功能。而且,如果你的数据很有价值,也不要完全相信

U D P 或

T C P 的检验和,因为这些都只是简单的检验和,不能检测出所有可能发生的差错。11.4 一个简单的例子

用我们自己编写的s o c k 程序生成一些可以通过t c p d u m p 观察的U D P 数据报:

bsdi % sock -v -u -i -n4 svr4 discard

connected on 140.252.13.35.1108 to 140.252.13.34.9

bsdi % sock -v -u -i -n4 -w0 svr4 discard

connected on 140.252.13.35.1110 to 140.252.13.34.9

第1次执行这个程序时,我们指定v e r b o s e 模式(- v )来观察e p h e m e r a l 端口号,指定U D P (- u )而不是默认的T C P ,并且指定源模式(- i )来发送数据,而不是读写标准的输入和输出。- n 4选项指明输出4份数据报(默认条件下为1 024),目的主机为s v r 4。在1 .12节描述了丢弃服务。每次写操作的输出长度取默认值1 024。

第2次运行该程序时我们指定- w 0,意思是写长度为0的数据报。两个命令的t c p d u m p 输出结果如图11 -6所示。

图11-6 向一个方向发送UDP 数据报时的t c p d u m p 输出

输出显示有四份1 024字节的数据报,接着有四份长度为0的数据报。每份数据报间隔几毫秒(输入第2个命令花了4 1秒的时间)。

在发送第1份数据报之前,发送端和接收端之间没有任何通信(在第 1 7章,我们将看到T C P 在发送数据的第1个字节之前必须与另一端建立连接)。另外,当收到数据时,接收端没有任何确认。在这个例子中,发送端并不知道另一端是否已经收到这些数据报。

最后要指出的是,每次运行程序时,源端的U D P 端口号都发生变化。第一次是11 08,然后是11 0。在1 .9节我们已经提过,客户程序使用e p h e m e r a l 端口号一般在1 024~5 000之间,正图11-5 检测到不同检验和差错的分组统计结果层次以太网检验和差错数近似总分组数

如我们现在看到的这样。

11.5 IP分片

正如我们在2 .8节描述的那样,物理网络层一般要限制每次发送数据帧的最大长度。任何时候I P层接收到一份要发送的I P数据报时,它要判断向本地哪个接口发送数据(选路),并查询该接口获得其M T U。I P把M T U与数据报长度进行比较,如果需要则进行分片。分片可以发生在原始发送端主机上,也可以发生在中间路由器上。

把一份I P数据报分片以后,只有到达目的地才进行重新组装(这里的重新组装与其他网络协议不同,它们要求在下一站就进行进行重新组装,而不是在最终的目的地)。重新组装由目的端的I P层来完成,其目的是使分片和重新组装过程对运输层(T C P和U D P)是透明的,除了某些可能的越级操作外。已经分片过的数据报有可能会再次进行分片(可能不止一次)。

I P首部中包含的数据为分片和重新组装提供了足够的信息。

回忆I P首部(图3 -1),下面这些字段用于分片过程。对于发送端发送的每份I P数据报来说,其标识字段都包含一个唯一值。该值在数据报分片时被复制到每个片中(我们现在已经看到这个字段的用途)。标志字段用其中一个比特来表示“更多的片”。除了最后一片外,其他每个组成数据报的片都要把该比特置1。片偏移字段指的是该片偏移原始数据报开始处的位置。另外,当数据报被分片后,每个片的总长度值要改为该片的长度值。

最后,标志字段中有一个比特称作“不分片”位。如果将这一比特置1,I P将不对数据报进行分片。相反把数据报丢弃并发送一个I C M P差错报文(“需要进行分片但设置了不分片比特”,见图6 -3)给起始端。在下一节我们将看到出现这个差错的例子。

当I P数据报被分片后,每一片都成为一个分组,具有自己的I P首部,并在选择路由时与其他分组独立。这样,当数据报的这些片到达目的端时有可能会失序,但是在I P首部中有足够的信息让接收端能正确组装这些数据报片。

尽管I P分片过程看起来是透明的,但有一点让人不想使用它:即使只丢失一片数据也要重传整个数据报。为什么会发生这种情况呢?因为I P层本身没有超时重传的机制——由更高层来负责超时和重传(T C P有超时和重传机制,但U D P没有。一些U D P应用程序本身也执行超时和重传)。当来自T C P报文段的某一片丢失后,T C P在超时后会重发整个T C P报文段,该报文段对应于一份I P数据报。没有办法只重传数据报中的一个数据报片。事实上,如果对数据报分片的是中间路由器,而不是起始端系统,那么起始端系统就无法知道数据报是如何被分片的。就这个原因,经常要避免分片。文献[Kent and Mogul 1987]对避免分片进行了论述。

使用U D P很容易导致I P分片(在后面我们将看到,T C P试图避免分片,但对于应用程序来说几乎不可能强迫T C P发送一个需要进行分片的长报文段)。我们可以用s o c k程序来增加数据报的长度,直到分片发生。在一个以太网上,数据帧的最大长度是 1 500字节(见图2 -1),其中1 472字节留给数据,假定I P首部为2 0字节,U D P首部为8字节。我们分别以数据长度为1471, 1472, 1473和1 474字节运行s o c k程序。最后两次应该发生分片:

bsdi % sock -u -i -nl -w1471 svr4 discard

bsdi % sock -u -i -nl -w1472 svr4 discard

bsdi % sock -u -i -nl -w1473 svr4 discard

bsdi % sock -u -i -nl -w1474 svr4 discard

相应的t c p d u m p输出如图11 -7所示。

11-7 观察UDP 数据报分片前两份U D P 数据报(第1行和第2行)能装入以太网数据帧,没有被分片。但是对应于写1 473字节的I P 数据报长度为1 501,就必须进行分片(第3行和第4行)。同理,写1 474字节产生的数据报长度为1 502,它也需要进行分片(第5行和第6行)。

当I P 数据报被分片后,t c p d u m p 打印出其他的信息。首先,fr a g 26304(第3行和第4行)和frag 26313(第5行和第6行)指的是I P 首部中标识字段的值。

分片信息中的下一个数字,即第3行中位于冒号和@号之间的1 480,是除I P 首部外的片长。两份数据报第一片的长度均为1 480:U D P 首部占8字节,用户数据占1 472字节(加上I P 首部的2 0字节分组长度正好为1 500字节)。第1份数据报的第2片(第4行)只包含1字节数据—剩下的用户数据。第2份数据报的第2片(第6行)包含剩下的2字节用户数据。

在分片时,除最后一片外,其他每一片中的数据部分(除I P 首部外的其余部分)必须是8字节的整数倍。在本例中,1 480是8的整数倍。

位于@符号后的数字是从数据报开始处计算的片偏移值。两份数据报第1片的偏移值均为0(第3行和第5行),第2片的偏移值为1480(第4行和第6行)。跟在偏移值后面的加号对应于I P 首部中3 bit 标志字段中的“更多片”比特。设置这一比特的目的是让接收端知道在什么时候完成所有的分片组装。

最后,注意第4行和第6行(不是第1片)省略了协议名(U D P )、源端口号和目的端口号。协议名是可以打印出来的,因为它在I P 首部并被复制到各个片中。但是,端口号在U D P 首部,只能在第1片中被发现。

发送的第3份数据报(用户数据为1 473字节)分片情况如图11 -8所示。需要重申的是,任何运输层首部只出现在第1片数据中。

另外需要解释几个术语:I P 数据报是指I P 层端到端的传输单元(在分片之前和重新组装之后),分组是指在I P 层和链路层之间传送的数据单元。一个分组可以是一个完整的I P 数据报,也可以是I P 数据报的一个分片。

图11-8 UDP 分片举例

20字节20字节8字节

8字节1472字节20字节1字节

IP 首部UDP 首部IP 首部

IP 首部

UDP 首部IP 数据报

UDP 数据(1473字节)

分组分组

11.6 ICMP 不可达差错(需要分片)

发生I C M P 不可达差错的另一种情况是,当路由器收到一份需要分片的数据报,而在I P 首部又设置了不分片(D F )的标志比特。如果某个程序需要判断到达目的端的路途中最小M T U 是多少—称作路径M T U 发现机制(2 .9节),那么这个差错就可以被该程序使用。

这种情况下的I C M P 不可达差错报文格式如图11 -9所示。这里的格式与图6 -10不同,因为在第2个32 bit 字中,16~31 bit 可以提供下一站的M T U ,而不再是0。

图11-9 需要分片但又设置不分片标志比特时的ICMP 不可达差错报文格式

如果路由器没有提供这种新的I C M P 差错报文格式,那么下一站的M T U 就设为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 -10所示。

图11-10 用来判断从n e t b 到s u n 的SLIP 链路MTU 的系统

在主机s u n 上运行t c p d u m p ,观察S L I P 链路,看什么时候发生分片。开始没有观察到分片,一切都很正常直到p i n g 分组的数据长度从5 00增加到6 00字节。可以看到接收到的回显请类型(3)

代码(4)检验和8字节下一站网络的MTU

未用(必须为0)IP 首部(包括选项)+原始IP 数据报中数据的前8字节

分片

分片用tcpdump 观察分片

ICMP 回显请求

求(仍然没有分片),但不见回显应答。

为了跟踪下去,也在主机b s d i 上运行t c p d u m p ,观察它接收和发送的报文。输出如图11 -11

所示。

图11-11 600字节的IP 数据报从s o l a r i s 主机p i n g 到b s d i 主机时的t c p d u m p 输出

首先,每行中的标记(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 00字节),但是s u n 外出的S L I P 接口M T U 为5 52。因此回显应

答需要进行分片,但是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 -12所示。

图11-12 例子中的分组交换

最后,在图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 500)。

11.7 用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 “不能分片”差错时(在上一节讨论ICMP 回显请求

ICMP 回显请求ICMP 回显请求

ICMP 回显应答ICMP 不可达:需要分片,

但又设置了DF 位

的)就减小分组的长度。如果路由器发送的I C M P 差错报文是新格式,包含出口的M T U ,那么就用该M T U 值来发送,否则就用下一个最小的M T U 值来发送。正如RFC 1191 [Mogul and Deering 1990]声明的那样,M T U 值的个数是有限的,因此在我们的程序中有一些由近似值构成的表,取下一个最小M T U 值来发送。

首先,我们尝试判断从主机

s u

n 到主机s l i p 的路径M T U ,知道S L I P 链路的M T U 为2 96。在这个例子中,路由器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 值。

全球互联网

作为一个实验,我们多次运行修改以后的t r a c e r o u t e 程序,目的端为世界各地的主机。可以到达1 5个国家(包括南极洲),使用了多个跨大西洋和跨太平洋的链路。但是,在这样做之前,作者所在子网与路由器n e t b 之间的拨号S L I P 链路M T U (见图11 -12)增加到1 500,与以太网相同。

在1 8次运行当中,只有其中2次发现的路径M T U 小于1 5 0 0。其中一个跨大西洋的链路M T U 值为5 7 2(其近似值甚至在RFC 11 9 1中也没有被列出),而路由器返回的是新格式的I C M P 差错报文。另外一条链路,在日本的两个路由器之间,不能处理1 500字节的数据帧,并且路由器没有返回新格式的I C M P 差错报文。把M T U 值设成1 006则可以正常工作。

从这个实验可以得出结论,现在许多但不是所有的广域网都可以处理大于5 12字节的分组。利用路径M T U 发现机制,应用程序就可以充分利用更大的M T U 来发送报文。

11.8 采用UDP 的路径MTU 发现

下面对使用U D P 的应用程序与路径M T U 发现机制之间的交互作用进行研究。看一看如果应用程序写了一个对于一些中间链路来说太长的数据报时会发生什么情况。

例子

由于我们所使用的支持路径M T U 发现机制的唯一系统就是Solaris 2.x ,因此,将采用它作为源站发送一份6 50字节数据报经s l i p 。由于s l i p 主机位于M T U 为2 96的S L I P 链路后,因此,任何长于2 68字节(2 96-2 0-8)且“不分片”比特置为1的U D P 数据都会使b s d i 路由器产生I C M P “不能分片”差错报文。图11 -13给出了拓扑结构和M T U 。

图11-13 使用UDP 进行路径MTU 发现的系统

可以用下面的命令行来产生6 50字节U D P 数据报,每两个U D P 数据报之间的间隔是5秒:solaris % s ock -u -i -n10 -w650 -p5 slip discard

图11 -14是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 76就行了。第一次分片(第5行)包含5 44字节的U D P 数据、8字节U D P 首部以及2 0字节I P 首部,因此,总I P 数据报长度是5 72字节。第2次分片(第6行)包含剩余的1 06字节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无法对单个在这里运行tcpdump 命令

将DF 比特置1的650字节UDP 数据报

ICMP 不能分片差错

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 应用程序写入可能被分片数据报时,该数据报将被丢弃。图11-14 使用UDP 路径MTU 发现

s o l a r i s 的I P 层所假设的最大数据报长度(5 76字节)是不正确的。在图11 -13中,我们看到,实际的M T U 值是2 96字节。这意味着经s o l a r i s 分片的数据报还将被b s d i 分片。图11 -15给出了在目的主机(s l i p )上所收集到的t c p d u m p 对于第一个到达数据报的输出结果(图11 -14的第5行和第6行)。

图11-15 从solaris 到达slip 的第一个数据报

在本例中,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 -16给出了t c p d u m p 输出结果的前6行。

与图11 -14一样,前两个数据报同样是将D F 比特置1后发送出去的。但是在知道了下一跳M T U 后,只产生了3个数据报片,而图11 -15中的b s d i 路由器则产生了4个数据报片。

图11-16

使用UDP

的路径MTU 发现

11.9 UDP 和ARP 之间的交互作用

使用U D P ,可以看到U D P 与A R P 典型实现之间的有趣的(而常常未被人提及)交互作用。我们用s o c k 程序来产生一个包含8 192字节数据的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 -17给出了t c p d u m p 的输出结果。

图11-17 在以太网上发送8192字节UDP 数据报时的报文交换

在这个输出结果中有一些令人吃惊的结果。首先,在第一个 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 r4发回7个,而不是6个A R P应答。

最后要指出的是,在最后一个A R P应答返回后,继续运行t c p d u m p程序5分钟,以看看s v r4是否会返回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 192字节。在以太网上,这些数据报以我们所指出的方式进行分片,如果适当的 A R P缓存入口发生超时,那么就可以看到这里所显示的现象。N F S将超时并重传,但是由于A R P的有限队列,第一个I P 数据报仍可能被丢弃。

11.10 最大UDP数据报长度

理论上,I P数据报的最大长度是6 5535字节,这是由I P首部(图3 -1)1 6比特总长度字段所限制的。去除2 0字节的I P首部和8个字节的U D P首部,U D P数据报中用户数据的最长长度为6 5507字节。但是,大多数实现所提供的长度比这个最大值小。

我们将遇到两个限制因素。第一,应用程序可能会受到其程序接口的限制。socket API提供了一个可供应用程序调用的函数,以设置接收和发送缓存的长度。对于UDP socket,这个长度与应用程序可以读写的最大U D P数据报的长度直接相关。现在的大部分系统都默认提供了可读写大于8 192字节的U D P数据报(使用这个默认值是因为8 192是N F S读写用户数据数的默认值)。

第二个限制来自于T C P/I P的内核实现。可能存在一些实现特性(或差错),使I P数据报长度小于6 5535字节。

作者使用s o c k程序对不同U D P数据报长度进行了试验。在SunOS 4.1.3下使用环回

接口的最大I P数据报长度是3 2767字节。比它大的值都会发生差错。但是从B S D/386到

SunOS 4.1.3的情况下,S u n所能接收到最大I P数据报长度为3 2786字节(即3 2758字节用

户数据)。在Solaris 2.2下使用环回接口,最大可收发I P数据报长度为6 5535字节。从

Solaris 2.2到AIX 3.2.2,发送的最大IP数据报长度可以是65535字节。很显然,这个限制

与源端和目的端的实现有关。

我们在3 .2节中提过,要求主机必须能够接收最短为5 76字节的I P数据报。在许多U D P应用程序的设计中,其应用程序数据被限制成5 12字节或更小,因此比这个限制值小。例如,我们在1 0.4节中看到,路径信息协议总是发送每份数据报小于 5 12字节的数据。我们还会在其他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 R4下的socket API(包括Solaris 2.x) 并不截断数据报。超出部分数据在后面的读取中返回。它也不通知应用程序从单个UDP数据报中多次进行读取操作。

TLI API不丢弃数据。相反,它返回一个标志表明可以获得更多的数据,而应用程序后面的读操作将返回数据报的其余部分。

在讨论T C P时,我们发现它为应用程序提供连续的字节流,而没有任何信息边界。T C P以应用程序读操作时所要求的长度来传送数据,因此,在这个接口下,不会发生数据丢失。

11.11 ICMP源站抑制差错

我们同样也可以使用U D P产生I C M P“源站抑制(source quench)”差错。当一个系统(路由器或主机)接收数据报的速度比其处理速度快时,可能产生这个差错。注意限定词“可能”。即使一个系统已经没有缓存并丢弃数据报,也不要求它一定要发送源站抑制报文。

图11 -18给出了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 00个1 024字节长数据报给s o l a r i s。我们将数据报发送给标准的丢弃服务,这样,这些数据报将被忽略:

bsdi % sock -u -i -w1024 -n100 solaris discard

图11 -19给出了与此命令行相对应的t c p d u m p输出结果

在这个输出结果中,删除了很多行,这只是一个模型。接收前 2 6个数据报时未发生差

错;我们只给出了第一个数据报的结果。然而,从第 2 7个数据报开始,每发送一份数据报,

就会接收到一份源站抑制差错报文。总共有26 +(7 4×2)= 174行输出结果。

图11-18 ICMP 源站抑制差错报文格式图11-19 来自路由器s u

n 的ICMP 源站抑制从

2 .10节的并行线吞吐率计算结果可以知道,以9600 b/s 速率传送1 024字节数据报只需要1秒时间(由于从s u n 到n e t b 的S L I P 链路的M T U 为5 52字节,因此在我们的例子中,20 + 8 +1 024字节数据报将进行分片,因此,其时间会稍长一些)。但是我们可以从图11 -19的时间中看出,s u n 路由器在不到1秒时间内就处理完所有的1 00个数据报,而这时,第一份数据报还未通过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.10节所讨论的那样,T C P 接受源站抑制差错报文,并将放慢在该连接上的数据传输速度)。其部分原因在于,在接收到源站抑制差错报文时,导致源站抑制的进程可能已经中止了。实际上,如果使用Unix 的t i m e 程序来测定s o c k 程序所运行的时间,其结果是它只运行了大约0 .5秒时间。但是从图11 -19中可以看到,在发送第一份数据报过后0 .71秒才接收到一些源站抑制,而此时该进程已经中止。其原因是我们的程序写入了 1 00个数据报然后中止了。但是所有的1 00个数据报都已发送出去—有一些数据报在输出队列中。

这个例子重申了U D P 是一个非可靠的协议,它说明了端到端的流量控制。尽管s o c k 程序成功地将1 00个数据报写入其网络,但只有2 6个数据报真正发送到了目的端。其他7 4个数据报类型(4)代码(0)

检验和8字节

未用(必须为0)IP 首部(包括选项)+原始IP 数据报中数据的前8字节

可能被中间路由器丢弃。除非在应用程序中建立一些应答机制,否则发送端并不知道接收端是否收到了这些数据。

11.12 UDP服务器的设计

使用U D P的一些蕴含对于设计和实现服务器会产生影响。通常,客户端的设计和实现比服务器端的要容易一些,这就是我们为什么要讨论服务器的设计,而不是讨论客户端的设计的原因。典型的服务器与操作系统进行交互作用,而且大多数需要同时处理多个客户。

通常一个客户启动后直接与单个服务器通信,然后就结束了。而对于服务器来说,它启动后处于休眠状态,等待客户请求的到来。对于U D P来说,当客户数据报到达时,服务器苏醒过来,数据报中可能包含来自客户的某种形式的请求消息。

在这里我们所感兴趣的并不是客户和服务器的编程方面([Stevens 1990]对这些方面的细节进行了讨论),而是U D P那些影响使用该协议的服务器的设计和实现方面的协议特性(我们在1 8.11节中对T C P服务器的设计进行了描述)。尽管我们所描述的一些特性取决于所使用U D P的实现,但对于大多数实现来说,这些特性是公共的。

11.12.1 客户IP地址及端口号

来自客户的是U D P数据报。I P首部包含源端和目的端I P地址,U D P首部包含了源端和目的端的U D P端口号。当一个应用程序接收到U D P数据报时,操作系统必须告诉它是谁发送了这份消息,即源I P地址和端口号。

这个特性允许一个交互U D P服务器对多个客户进行处理。给每个发送请求的客户发回应答。

11.12.2 目的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 T ADDR socket选项提供了这个功能。对于本文中使用的系统,只有B S D/386、4 .4B S D和AIX 3.2.2支持该选项。S V R4、SunOS 4.x和Solaris 2.x 都不支持该选项。

11.12.3 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 56字节(-R ),其每次应用程序读取的大小也是这个数(- r )。标志- P 30表示创建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 111111111 1 1字节的数据(新行)

2 22222222 1 0字节的数据(新行)

3 3333333333 1 2字节的数据(新行)

目的地址是广播地址(1 40.252.13.63)。我们同时也在主机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 444444444444

1 4字节的数据(新行)5 55555555555555

1 6字节的数据(新行)6 66666669字节的数据(新行)

首先,我们早些时候在b s d i 上所看到的结果表明,应用程序只接收到2个数据报:来自s u n 的第一个全1报文,和来自s v r 4的第一个全4报文。其他4个数据报看来全被丢弃。

图11 -20给出的t c p d u m p 输出结果表明,所有6个数据报都发送给了目的主机。两个客户的数据报以交替顺序键入:第一个来自s u n ,然后是来自s v r 4的,以此类推。同时也可以看出,全部6个数据报大约在1 2秒内发送完毕,也就是在服务器休眠的3 0秒内完成的。

图11-20 两个客户发送UDP 数据报的t c p d u m p 输出结果

我们还可以看到,服务器的-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 输入却是

L I F O (后进先出)的。

11.12.4 限制本地IP 地址

大多数U D P 服务器在创建U D P 端点时都使其本地I P 地址具有通配符( w i l d c a r d )的特点。这就表明进入的U D P 数据报如果其目的地为服务器端口,那么在任何本地接口均可接收到它。例如,我们以端口号7 77启动一个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 端点。

本地地址以* .7777格式打印,星号表示任何本地I P 地址。

当服务器创建端点时,它可以把其中一个主机本地I P 地址包括广播地址指定为端点的本地I P 地址。只有当目的I P 地址与指定的地址相匹配时,进入的U D P 数据报才能被送到这个端点。用我们的s o c k 程序,如果在端口号之前指定一个I P 地址,那么该I P 地址就成为该端点的本地I P 地址。例如:

sun % sock -u -s 140.252.1.29 7777

就限制服务器在S L I P 接口( 140.252.1.29)处接收数据报。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 40.252.13.35向该服务器发送一份数据报,那么将返回一个I C M P 端口不可达差错。服务器永远看不到这份数据报。这种情形如图11 -21所示。

图11-21 服务器本地地址绑定导致拒绝接收UDP 数据报

有可能在相同的端口上启动不同的服务器,每个服务器具有不同的本地

I P 地址。但是,

一般必须告诉系统应用程序重用相同的端口号没有问题。使用sockets API 时,必须指定S O _R E U S E A D D R s o c k e t 选项。在s o c k 程序中是通过-A

选项来完成的。

在主机s u n 上,可以在同一个端口号(8 888)上启动5个不同的服务器:

对于SLIP 链路

对于以太网

对于环回接口

对于以太网广播

其他(IP 地址通配)

除了第一个以外,其他的服务器都必须以-A 选项启动,告诉系统可以重用同一个端口号。

5

个服务器的

n e t s t a t 输出结果如下所示:在这种情况下,到达服务器的数据报中,只有带星号的本地

I P 地址,其目的地址为

1 40.252.1.255,因为其他4个服务器占用了其他所有可能的I P 地址。如果存在一个含星号的I P 地址,那么就隐含了一种优先级关系。如果为端点指定了特定I P 地址,那么在匹配目的地址时始终优先匹配该I P 地址。只有在匹配不成功时才使用含星号的端点。

11.12.5 限制远端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 40

.252.13.35(即主机b s d i )和远端端口号4444 。服务器的有名端口号为5555。如果运行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 40.252.13.33相连。

图11 -22总结了U D P 服务器本身可以创建的三类地址绑定。

图11-22 为UDP 服务器指定本地和远端IP 地址及端口号

在所有情况下,l p o r t 指的是服务器有名端口号,l o c a l I P 必须是本地接口的I P 地址。表中这三行的排序是U D P 模块在判断用哪个端点接收数据报时所采用的顺序。最为确定的地址(第一行)首先被匹配,最不确定的地址(最后一行I P 地址带有两个星号)最后进行匹配。11.12.6 每个端口有多个接收者

尽管在R F C 中没有指明,但大多数的系统在某一时刻只允许一个程序端点与某个本地I P

地址及U D P端口号相关联。当目的地为该I P地址及端口号的U D P数据报到达主机时,就复制一份传给该端点。端点的I P地址可以含星号,正如我们前面讨论的那样。

例如,在SunOS 4.1.3中,我们启动一个端口号为9 999的服务器,本地I P地址含有星号:sun % sock -u -s 9999

接着,如果启动另一个具有相同本地地址和端口号的服务器,那么它将不运行,尽管我们指定了- A选项:

sun % sock -u -s 9999我们预计它会失败

can't bind local address: Address already in use

sun % sock -u -s -A 9999因此,这次尝试- A参数

can't 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 R s o c k e t选项)。

4.4B 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 P地址和端口号处有多个端点时,就向每个端点传送一份数据报的复制(端点的本地I P地址可以含有星号,它可匹配任何目的I P地址)。但是,如果U D P数据报到达的是一个单播地址,那么只向其中一个端点传送一份数据报的复制。选择哪个端点传送数据取决于各个不同的系统实现。

11.13 小结

U D P是一个简单协议。它的正式规范是RFC 768 [Postel 1980],只包含三页内容。它向用户进程提供的服务位于I P层之上,包括端口号和可选的检验和。我们用U D P来检查检验和,并观察分片是如何进行的。

接着,我们讨论了I C M P不可达差错,它是新的路径M T U发现功能中的一部分(2 .9节)。用Tr a c e r o u t e和U D P来观察路径M T U发现过程。还查看了U D P和A R P之间的接口,大多数的A R P实现在等待A R P应答时只保留最近传送给目的端的数据报。

当系统接收I P数据报的速率超过这些数据报被处理的速率时,系统可能发送I C M P源站抑制差错报文。使用U D P时很容易产生这样的I C M P差错。

习题

11.1 在11 .5节中,向U D P数据报中写入1 473字节用户数据时导致以太网数据报片的发生。在

采用以太网IEEE 802封装格式时,导致分片的最小用户数据长度为多少?

11.2 阅读RFC 791[Postel 1981a],理解为什么除最后一片外,其他片中的数据长度均要求为

8字节的整数倍?

11.3 假定有一个以太网和一份8 192字节的U D P数据报,那么需要分成多少个数据报片,每个

数据报片的偏移和长度为多少?

11.4 继续前一习题,假定这些数据报片要经过一条M T U为5 52的S L I P链路。必须记住每一个

相关文档