TCP/IP协议—UDP 用户数据报协议

风尘

文章目录

  1. 1. UDP 首部
  2. 2. IP 分片
  3. 3. ICMP 不可达差错
  4. 4. 路径 MTU 发现
    1. 4.1. traceroute 确定路径 MTU
    2. 4.2. 采用 UDP 的路径 MTU 发现
  5. 5. UDP 数据报最大长度
  6. 6. ICMP 源站抑制差错
  7. 7. 广播和多播
    1. 7.1. 广播
    2. 7.2. 多播
  8. 8. IGMP
    1. 8.1. 报文格式
    2. 8.2. 加入多播组
    3. 8.3. IGMP 报告和查询

[TOC]

UDPUser Datagram Protocol)是一个简单的面向数据报的运输层协议,进程的每个输出操作都正好产生一个UDP数据报并组装成一个待发送的IP数据报。这与面向流字符的协议不同,如TCP,应用程序产生的全部数据与真正发送的单个IP数据报可能没有什么联系。

UDP不提供可靠性,它把应用程序传给IP层的数据发送出去,但是并不保证它们能到达目的地。

UDP 首部

UDP首部字段:

端口号 表示发送进程和接收进程。

UDP 长度 表示UDP首部和UDP数据的字节长度。最小值为8字节(可以发送0字节数据报),IP数据报指的是数据报全长,因此UDP数据报长度是全长送去IP数据报首部长度。

检验和 检验和覆盖UDP首部和UDP数据。它与IP首部检验和只覆盖IP首部不同。并且它的检验和是可选的。如果发送端没有计算检验和而接收端检测到检验和有差错,那么UDP数据报就要被悄悄地丢弃。不产生任何差错报文(当IP层检测到IP首部检验和有差错时也这样做)。

计算方法与IP首部检验和类似,不同之处有:

  • UDP 数据报长度可以为奇数字节,但是检验和算法是把若干个16bit字相加。解决方法是必要时在最后增加填充字节0,这只是为了检验和的计算(也就是说,可能增加的填充字节不被传送)。

  • UDP数据报TCP段都包含一个12字节长度的伪首部,它是为国计算检验和设置的。伪首部包含IP首部一些字段。其目的是让UDP两次检查数据是否已经正确到达目的地。

    UDP 伪首部UDP 伪首部

上图是一个奇数字节长度的UDP数据报,因而在计算检验和时需要在尾部加上 “ 填充字节(0) ”;

UDP 长度 字段在检验和计算中出现两次。

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

尽管UDP检验和是可选的,但是它们应该总是在用。在单个局域网中关闭检验和可能是可以被接受的,但是在数据报通过路由器时,通过对链路层数据帧进行循环冗余检验(如以太网或令牌环数据帧)可以检测到大多数的差错,导致传输失败。

Host Requirements RFC声明,UDP检验和选项在默认条件下是打开的。它还声明,如果发送端已经计算了检验和,那么接收端必须检验接收到的检验和(如接收到检验和不为0)。但是,许多系统没有遵守这一点,只是在出口检验和选项被打开时才验证接收到的检验和。

IP 分片

物理网络层一般要限制每次发送数据帧的最大长度,任何时候IP层接收到一份要发送的数据报时,它先要判断向本地哪个接口发送数据(选路),并查询该接口获得其MTUIPMTU与数据报长度进行比较,如果需要则进行分片。分片可以发生在原始发送端主机上,也可以发生在中间路由器上。

把一份IP数据报分片以后,只有到达目的地才进行重新组装(这里的重新组装与其他网络协议要求在“下一跳”就进行重新组装不同)。重新组装由目的IP层来完成,其目的是使分片和重新组装过程对运输层(TCPUDP)是透明的。

已经分片过的数据报有可能会再次进行分片(可能不止一次)。IP首部中包含的数据为分片和重新组装提供了足够的信息。

IP首部IP首部

IP首部分片字段如上图:

标识 字段,每份IP数据报标识字段包含一个唯一值,该值在数据报分片时被复制到每个片中。

标志 字段,目前只有两位有意义:

  • 第一位 没有被使用

  • 第二位 DF(dont’t fragment),当DF=1IP将不对数据报进行分片。

  • 第三位 MF(more fragment),当MF=1时表示还有更多分片,只有最后一个分片该位置0

片偏移 字段,指该片偏移原始数据报开始处的位置。

当数据报被分片后,每个片的总长度字段值要改为该片的长度值。

UDP即使只丢失一片数据也要重传整个数据报。为什么会发生这种情况呢?

因为IP层本身没有超时重传的机制——由更高层来负责超时和重传,TCP有超时和重传机制,但UDP没有,一些U D P应用程序本身也执行超时和重传。

当来自TCP报文段的某一片丢失后,TCP在超时后会重发整个TCP报文段,该报文段对应于一份IP数据报。没有办法只重传数据报中的一个数据报片。事实上,如果对数据报分片的是中间路由器,而不是起始端系统,那么起始端系统就无法知道数据报是如何被分片的。就这个原因,经常要避免分片。

ICMP 不可达差错

发生ICMP不可达差错的另一种情况,是当路由器收到一份需要分片的数据报,而在IP首部又设置了不分片(DF)的标志比特。

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

注意报文中的 下一跳网络的MTU 字段,如果路由器没有提供这种新的ICMP差错报文格式,那么该字段设置为0

新版的路由器需求RFC [Almquist 1993]声明,在发生这种ICMP不可达差错时,路由器必须生成这种新格式的报文。

路径 MTU 发现

traceroute 确定路径 MTU

采用 UDP 的路径 MTU 发现

UDP 数据报最大长度

IP数据报最大长度是65535字节,这是由IP首部16bit总长度字段决定的。除去20字节的IP首部和8字节的UDP首部,UDP数据报中用户数据的最大长度为65507字节。但是大多数实现所提供的长度比这个值小。

限制因素

  • 应用程序可能受到其程序接口的限制。如,socket API提供了一个可供应用程序调用的函数,以设置接收和发送缓存的长度,这个长度与应用程序可以读写的最大UDP数据报的长度直接相关。现在大部分系统默认都提供了可读写大于8192字节的UDP数据报(使用这个默认值是因为8192NFS读写用户数据数的默认值)。

  • TCP/IP内核实现的限制。可能存在一些实现特性(或差错),使IP数据报长度小于65535字节。

    由于IP能够发送或接收特定长度的数据报并不意味着接收应用程序可以读取该长度的数据。因此,UDP编程接口允许应用程序指定每次返回的最大字节数。如果接收到的数据报长度大于应用程序所能处理的长度,那么会发生什么情况呢?

    不幸的是,该问题的答案取决于编程接口和实现。

ICMP 源站抑制差错

当一个系统(主机或路由器)接收数据报的速度比其处理速度快,可能产生这个差错。之所以是可能这个词是因为即使一个系统已经没有缓存并丢弃数据报,也不要求它一定要发送源站抑制报文。

ICMP 源站抑制差错报文ICMP 源站抑制差错报文

RFC 1009 [Braden and Postel 1987]要求路由器在没有缓存时产生源站抑制差错报文,但是新的Router Requirements RFC [Almquist 1993]对此作了修改,提出路由器不应该产生源站抑制差错报文。由于源站抑制要消耗网络带宽,且对于拥塞来说是一种无效而不公平的调整,因此现在人们对于源站抑制差错的态度是不支持的。

广播和多播

IP地址总共有三种:单播地址、多播地址和广播地址。其中广播地址和多播地址仅应用于UDP,它们对需将报文同时传往多个接收者的应用来说十分重要。

TCP是一个面向连接的协议,它意味着分别运行于两主机(由IP地址确定)内的两进程(由端口号确定)间存在一条连接。

通常每个以太网帧仅发往单个目的主机,目的地址指明单个接收接口,因而称为单播(unicast)。在这种方式下,任意两个主机的通信不会干扰网内其他主机(可能引起争夺共享信道的情况除外)。

有时一个主机要向网上的所有其他主机发送帧,这就是广播(broadcast)。通过ARPRARP可以看到这一过程。

多播(multicast) 处于单播和广播之间,帧仅传送给属于多播组的多个主机。

大多数的网卡经过配置都能接收目的地址为多播地址或某些子网多播地址的帧。对于以太网,当地址中最高字节的最低位设置为1时表示该地址是一个多播地址,用十六进制可表示为01:00:00:00:00:00(以太网广播地址ff:ff:ff:ff:ff:ff可看作是以太网多播地址的特例)。

使用广播的问题在于它增加了对广播数据不感兴趣主机的处理负荷。多播的出现减少了对应用不感兴趣主机的处理负荷。使用多播,主机可加入一个或多个多播组。这样,网卡将获悉该主机属于哪个多播组,然后仅接收主机所在多播组的那些多播帧。

广播

下表为广播地址划分,其中-1表示所有比特位全为10表示所有比特位全为0netidsubnetid表示不全为01的对应字段。

网络号 子网号 主机号 源端 目的端 描述
-1 -1 不可能 OK 受限制广播(永远不被转发)
netid -1 不可能 OK 以网络为目的向netid广播
netid subnetid -1 不可能 OK 以子网为目的向netidsubnetid广播
netid -1 -1 不可能 OK 以所有子网为目的向netid广播

受限制广播 地址是255.255.255.255,该地址用于主机配置过程中IP数据报的目的地址,此时主机可能不知道它所在的网络掩码,甚至连它的IP地址也不知道(如主机启动过程中)。

在任何情况下,路由器都不转发目的地址为受限的广播地址的数据报,这样的数据报仅出现在本地网络中。

指向网络的广播 地址是主机号全为1的地址。A类网络广播地址为netid.255.255.255,其中netidA类网络的网络号。

一个路由器必须转发指向网络的广播,但它也必须有一个不进行转发的选择。

指向子网的广播 地址为主机号全为1且具有特定子网号(subnetid)的地址。作为子网直接广播地址的IP地址需要了解子网的掩码。

如路由器收到发往128.1.2.255的数据报,当B类网络128.1的子网掩码为255.255.255.0时,该地址就是指向子网的广播地址;但如果该子网的掩码为255.255.254.0,该地址就不是指向子网的广播地址。

  子网掩码:255.255.255.0                        子网掩码:255.255.254.0
  |
  V
  10000000 00000001 00000010 11111111          10000000 00000001 00000010 11111111
& 11111111 11111111 11111111 00000000        & 11111111 11111111 11111110 00000000
—————————————————————————————————————        —————————————————————————————————————
  10000000 00000001 00000010 00000000          10000000 00000001 00000011 00000000

  128      1        2        0                 128      1        3        0

计算结果如上,当子网的掩码为255.255.254.0时,IP地址为128.1.3.0其中子网地址为3,所以地址128.1.2.255就不是指向子网2的广播地址了。

指向所有子网的广播 地址为子网号全为1,主机号也全为1的地址。指向所有子网的广播也需要了解目的网络的子网掩码,以便与指向网络的广播地址区分开。

如子网掩码为255.255.255.0,那么IP地址128.1.255.255是一个指向所有子网的广播地址。

通过子网掩码255.255.255.0可以获得主机与子网号的分界线,即0表示的最后8bit是主机号;而通过128可以知道是B类地址,所以前16bit是由2bit前缀1014bit网络号组成,所以接下来8bit则表示子网号。根据指向所有子网的广播地址划分规则就可以写出该IP地址,即最后16bit的子网号和主机号均为1255,即最终IP地址为128.1.255.255

如果网络没有划分子网,这就是一个指向网络的广播。

RFC 922要求将一个指向所有子网的广播传送给所有子网,但当前的路由器没有这么做。因为一个因错误配置而没有子网掩码的主机会把它的本地广播传送到所有子网。

IP地址为128.1.2.3的主机没有设置子网掩码,它的广播地址在正常情况下的默认值是128.1.255.255。但如果子网掩码被设置为255.255.255.0,那么由错误配置的主机发出的广播将指向所有的子网。

B类地址128的默认子网掩码是255.255.0.0,此时128.1.255.255广播地址就是一个指向网络的广播;当子网掩码被错误设置为255.255.255.0时,该广播地址就变成了指向所有子网的广播

多播

IP多播提供两类服务:

  • 向多个目的地址传送数据。如交互式会议系统和向多个接收者分发邮件或新闻。如果不采用多播,目前这些应用大多采用TCP来完成(向每个目的地址传送一个单独的数据复制)。然而,即使使用多播,某些应用可能继续采用TCP来保证它的可靠性。
  • 客户对服务器的请求。如,无盘工作站需要确定启动引导服务器。目前,这项服务是通过广播来提供的,但是使用多播可降低不提供这项服务主机的负担。

能够接收发往一个特定多播组地址数据的主机集合称为主机组 (host group)。一个主机组可跨越多个网络。主机组中成员可随时加入或离开主机组。主机组中对主机的数量没有限制,同时不属于某一主机组的主机可以向该组发送信息。

一些多播组地址被 互联网数字分配机构(The Internet Assigned Numbers Authority,IANA) 确定为知名地址。它们也被当作永久主机组,这和TCPUDP中的熟知端口相似。同样,这些知名多播地址在RFC最新分配数字中列出。注意这些多播地址所代表的组是永久组,而它们的组成员却不是永久的。

224.0.0.1代表该子网内的所有系统组;224.0.0.2代表该子网内的所有路由器组;224.0.1.1用作网络时间协议NTP224.0.0.9用作RIP-2224.0.1.2用作SGI公司的dogfight应用。

多播组地址到以太网地址的转换

IANA拥有一个以太网地址块,即高位24bit00:00:5e(十六进制表示),该地址块所拥有的地址范围从00:00:5e:00:00:0000:00:5e:ff:ff:ffIANA将其中一半分配为多播地址。为了指明一个多播地址,任何一个以太网地址的首字节必须是01。所以IP多播相对应的以太网地址范围从01:00:5e:00:00:0001:00:5e:7f:ff:ff

这种地址分配将使以太网多播地址中的23bitIP多播组号对应起来,通过将多播组号中的低位23bit映射到以太网地址中的低位23bit实现。

D类IP地址对到以太网多播地址的映射D类IP地址对到以太网多播地址的映射

由于多播组号中的最高5bit在映射过程中被忽略,因此每个以太网多播地址对应的多播组是不唯一的。32 个不同的多播组号被映射为一个以太网地址。见下面示例。

多播地址`224.128.64.32`,十六进制表示为`e0.80.40.20`,后23位二进制表示为` 0000000 01000000 00100000;
多播地址`224.0.64.32`,十六进制表示为`e0:00:40:20`,后23位二进制表示为` 0000000 00101000 00100000

根据上图映射规则将其转换成以太网地址均为`01:00:5e:00:40:20`。

既然地址映射是不唯一的,那么设备驱动程序或IP层(见下图展示了主机对由信道传送过来帧的过滤过程)就必须对数据报进行过滤。因为网卡可能接收到主机不想接收的多播数据帧。另外,如果网卡不提供足够的多播数据帧过滤功能,设备驱动程序就必须接收所有多播数据帧,然后对它们进行过滤。

协议栈各层对收到帧的过滤过程协议栈各层对收到帧的过滤过程

局域网网卡趋向两种处理类型

  • 网卡根据对多播地址的散列值实行多播过滤,这意味仍会接收到不想接收的多播数据;
  • 网卡只接收一些固定数目的多播地址,这意味着当主机想接收超过网卡预先支持多播地址以外的多播地址时,必须将网卡设置为 多播混杂(multicast promiscuous) 模式。

这两种类型的网卡仍需要设备驱动程序检查收到的帧是否真是主机所需要的。

即使网卡实现了完美的多播过滤(基于48bit的硬件地址),由于从DIP地址到48bit的硬件地址的映射不是一对一的,过滤过程仍是必要的。

尽管存在地址映射不完美和需要硬件过滤的不足,多播仍然比广播好。

单个物理网络的多播过程

多播进程将目的IP地址指明为多播地址,设备驱动程序将它转换为相应的以太网地址,然后把数据发送出去。这些接收进程必须通知它们的IP层,它们想接收的发往给定多播地址的数据报,并且设备驱动程序必须能够接收这些多播帧,这个过程就是 加入一个多播组 。当一个主机收到多播数据报时,它必须向属于那个多播组的每个进程均传送一个复制,因为一个主机上可能存在多个属于同一多播组的进程。

单个物理网络以外的多播 需要通过路由器转发多播数据时,复杂性就增加了。需要有一个协议让多播路由器了解确定网络中属于确定多播组的任何一个主机,这个协议就是Internet组管理协议(IGMP)。

IGMP

因特网组管理协议(Internet Group Management Protocol,ICMP) ,它让一个物理网络上的所有系统知道主机当前所在的多播组。多播路由器需要这些信息以便知道多播数据报应该向哪些接口转发。

IGMP报文封装在IP数据报中IGMP报文封装在IP数据报中

ICMP一样,IGMP也被当作IP层的一部分,通过IP数据报进行传输。区别在于IGMP有固定长度8字节,没有可选数据。

报文格式

IGMP报文格式IGMP报文格式

IGMP 版本 字段,值为1

IGMP 类型 字段,值为1表明是由多播路由器发出的查询报文;值为2表明是主机发出的报告报文。

检验和 字段,与ICMG协议相同。

组地址 字段,为DIP地址。在查询报文中设置为0;在报告报文中为要参加的组地址。

加入多播组

多播的基础就是一个进程的概念(操作系统执行的一个程序),该进程在一个主机的给定接口上加入了一个多播组。在一个给定接口上的多播组中的成员是动态的,它随时因进程加入和离开多播组而变化。

这里所指的进程必须以某种方式在给定的接口上加入某个多播组。进程也能离开先前加入的多播组。这些是一个支持多播主机中任何API所必需的部分。

多播组中的成员是与接口相关联的,一个进程可以在多个接口上加入同一多播组。

主机必须保留一个表,此表中包含所有至少含有一个进程的多播组以及多播组中的进程数量。

IGMP 报告和查询

多播路由器使用IGMP报文来记录与该路由器相连网络中组成员的变化情况。规则如下:

  • 当第一个进程加入一个组时,主机就发送一个ICMP报告。如果一个主机的多个进程加入同一组,只发送一个IGMP报告。这个报告被发送到进程加入组所在的同一接口上。
  • 进程离开一个组时,主机不发送 IGMP报告,即便是组中的最后一个进程离开。主机知道在确定的组中已不再有组成员后,在随后收到的IGMP查询中就不再发送报告报文。
  • 多播路由器定时发送IGMP查询来了解是否还有任何主机包含有属于多播组的进程。多播路由器必须向每个接口发送一个IGMP查询。因为路由器希望主机对它加入的每个多播组均发回一个报告,因此IGMP查询报文中的组地址被设置为0
  • 主机通过发送IGMP报告来响应一个IGMP查询,对每个至少还包含一个进程的组均要发回IGMP报告。

使用这些查询和报告报文,多播路由器对每个接口保持一个表,表中记录接口上至少还包含一个主机的多播组。当路由器收到要转发的多播数据报时,它只将该数据报转发到(使用相应的多播链路层地址)还拥有属于那个组主机的接口上。

IGMP查询与报告IGMP查询与报告

实现细节

  • 当一个主机首次发送IGMP报告时,并不保证该报告被可靠接收(因为使用的IP交付服务)。下一报告将在间隔一段时间后发送,时间间隔由主机在010秒的范围内随机选择。
  • 当一个主机收到路由器发出的查询后,并不立即响应,而是经过一定的时间间隔后才发出响应(主机必须对它参加的每个组均发送一个响应)。 既然参加同一多播组的所有主机均发送一个报告,所以可将它们的发送间隔设置为随机时延。

在一个物理网络中的所有主机将收到同组其他主机发送的所有报告,因为如上图所示的报告中的目的地址是组地址。这意味着如果一个主机在等待发送报告的过程中,却收到了发自其他主机的相同报告,则该主机的响应就可以不必发送了。因为多播路由器并不关心有多少主机属于该组(甚至不关心哪些主机属于一个多播组),而只关心该组是否还至少拥有一个主机。

生存时间

在默认情况下,待传多播数据报的TTL被设置为1,这将使多播数据报仅局限在同一子网内传送。更大的TTL值能被多播路由器转发。

对发往一个多播地址的数据报从不会产生ICMP差错。当TTL值为0时,多播路由器也不产生ICMP“超时”差错。

通过增加TTL值的方法,一个应用程序可实现对一个特定服务器的扩展环搜索 (expanding ring search)。第一个多播数据报以TTL等于1发送。如果没有响应,就尝试将TTL设置为2然后3,等等。在这种方式下,该应用能找到以跳数来度量的最近的服务器。

224.0.0.1224.0.0.255的特殊地址空间用于多播范围不超过1的应用。不管TTL值是多少,多播路由器均不转发目的地址为这些地址中的任何一个地址的数据报。