【TCP/IP详解 卷一:协议】第十一章 UDP 用户数据报协议
11.1 引言
UDP 是一个简单的 面向数据报 的运输层协议:进程的每个 输出操作 都正好产生一个 UDP数据报,并且组装成一份待发送的IP数据报。
这与 TCP 不一样,它是 面向流字符 的协议,应用层程序 产生的全体数据 与 真正发送的单个IP数据报 可能没有联系。
UDP协议并不提供超时重传,出错重传等功能,也就是说其是 不可靠(unreliable)的协议。
UDP 把应用程序传给IP层的数据发送出去,但是并不能保证它们都能到达目的地。
应用程序必须关心 IP数据报 的长度。如果它超过网络的MTU(最大传输单元),那么就要对 IP数据报 进行分片。路径MTU:两台主机之间的路径中 最小的MTU。
11.2 UDP首部
该部分参考资料:详解学习笔记 UDP
UDP首部:
端口号表示 发送进程 和 接收进程。
这里教材讲的不清不楚的。引用一段别人所写的博客。
由于很多软件需要用到UDP协议,所以UDP协议必须通过某个标志用以区分不同的程序所需要的数据包。端口号的功能就在于此,例如某一个UDP程序A在系统中注册了3000端口,那么,以后从外面传进来的目的端口号为3000的UDP包都会交给该程序。端口号理论上可以有2^16这么多。因为它的长度是16个bit。
TCP/IP协议族中用端口号来标识进程;
端口号 是在 0 到 65535 之间的 整数;
客户程序 随机选取的 临时端口号;
每一种服务器程序 被分配了 确定的全局一致的 熟知端口号;
每一个客户进程 都知道 相应的服务器进程的 熟知端口号。
也就是说,根据端口号,可以知道它所代表的是哪一个进程。
在之前的内容里面,有介绍 TCP 和 UDP 通过 目的端口号 来 分用 来自IP层的数据 的过程。由于IP层 已经把 IP数据报 分配给了 TCP 或者是 UDP(通过 IP数据报 的 协议字段,TCP值为3,UDP值为4),所以 TCP端口号 由 TCP 查看,UDP端口号 由 UDP 查看。
UDP数据报 长度字段 指的是 UDP首部 和 UDP数据 的字节长度,而 IP数据报 长度字段指的是数据报全长。那么 UDP数据报 长度字段 的值 = IP数据报 长度字段 的值 - IP数据报首部 的长度。
11.3 UDP 检验和:保证数据的完整性
该部分参考资料:UDP协议及包格式
UDP 检验和的 目的:保证数据的完整性。
UDP 检验和 覆盖 UDP首部 和 UDP数据,而 IP 检验和只覆盖首部,并不覆盖任何数据。
TCP 和 UDP 都有检验和,UDP是可选的,而TCP是必需的。
UDP 检验和的求法利用了和 IP 检验和 求法类似的 16bit 的 二进制反码求和。但是有不同的地方。
检验和求法 不同之一:填充字段
UDP 数据报的长度可以是奇数字节,但 检验和算法 是把 若干个16 bit字相加。
解决方法是:在最后增加填充字节0。这只是为了 检验和的计算(也就是说,这些可能增加的 填充字节 不会被传送)。
检验和求法 不同之二:伪首部
为了 计算检验和 而在 UDP数据报和TCP段 设置一个十二字节长的 伪首部。
伪首部 包含 IP首部的一些字段:32位源IP地址,32位目的IP地址,8位协议字段。目的是让 UDP 两次检测数据是否已经准确到达目的地。没有准确到达目的地,比如 IP没有接受地址不是本机的数据报,以及 IP 没有把 应该 传给另一高层的数据报 传输给UDP。
如果 发送端 没有计算检验和(传送的检验和为0),而接收端 检测到检验和有差错,UDP数据报就会被悄悄的丢弃,不产生任何差错报文。
总而言之,UDP 在 完成进程 到 进程的通信 中 提供了 有限的差错检验功能。
11.5 IP分片
物理网络层一般要限制每次发送数据帧的最大长度,任何时候 IP层 接收到一份 待发送的 IP数据报 的时候,它要判断向本地哪个接口发送数据(选路),并查询该接口获得MTU。IP 比较 MTU 和 数据报长度,如果需要的话(数据报长度 > MTU),则进行 IP分片。
分片 可以发生在 原始发送端主机上,也可以发生在中间路由器上面。
把 IP数据报 分片之后,只有 到达目的地 才重新组装。
重新组装 由 目的端的IP层 进行,目的:让分片和重新组装的过程 对 运输层(TCP/UDP) 透明。IP首部中包含的数据为 重新组装 提供信息。
分片之后的数据报可能再进行分片。分片之后 每一片都是一个 分组,具有自己的 IP首部。
回忆 IP首部
IP首部 中用于 分片和重组 的部分:
- 标识字段
- 标志字段
- 片偏移字段
标识字段:16bit,对于发送端发送的每一个IP数据报来说,这个标识字段有一个唯一值,也就是说,标识字段是用于区分数据报的。
在数据报分片的时候,被复制到每个片中。
标志字段:很重要,有3bit。
- 一位无效位
- 一位表示 是否有更多的片(MF, More Fragment),除了最后一片(MF = 0)之外,其余片 值均为1(MF = 1 代表后面还有片)。让接收端知道什么时候完成分片组装。
- DF (Don't Fragment),表示无法分片。
片偏移字段:说明了在原来的数据报中的相对位置。
回到IP分片
IP分片 过程看起来是透明的,但是:即使只丢失一片数据报的分片,也要重传一整个数据报。没有办法只重传数据报中的某一个数据报片。
原因是:IP层没有超时重传机制,由更高层负责超时重传(TCP有,UDP没有,但是 UDP的一些应用程序 本身也执行 超时和重传)。TCP在超时之后,会重新发送整个TCP报文段,对应于一个IP数据报。
起始端系统不清楚IP报文是怎么被分片的。
在分片时,除了最后一片,其他每一片的数据部分 都是 8字节 的整数倍。
术语的解释
IP数据报 指的是 端对端 的传输单元(分片之前,重新组装之后)。
分组 指的是 在 IP层 和 数据链路层 之间传送的数据单元。
分组 可以是 一个完整的IP数据报,也可以是IP数据报的一个分片。
ICMP不可达差错(需要分片)
发送 ICMP不可达差错报文 的另外一种情况是:当路由器收到一份需要分片的数据报,而在 IP数据报的首部 又设置了 DF(不分片) 的标志比特。
可以利用这个报文(含下一站网络的MTU) 判断到达目的端的路径MTU(最小MTU),称作 路径MTU发现机制。
如果路由器没有提供这种ICMP差错报文格式,则把下一站的MTU设为0。
在点对点链路中,不要求两个方向上的MTU为相同值。
11.7 利用Traceroute 确定路径MTU
Traceroute 所要做的:发送分组,设置“不分片”标志比特。Traceroute 程序本身也是利用 IP数据报 中的TTL字段。
11.9 UDP 和 ARP 之间的交互作用
使用 UDP,可以看到 UDP 和 ARP 典型实现之间的有趣的(但常常未被提交的)交互作用。
假定此时主机的 ARP缓存是清空的,那么在发送第一个数据报片的时候,就必须交换 ARP请求 和 应答。
那么此时就提出了两个问题:
- 在接收到应答之前,其余数据报是否做好了发送准备?
- 如果做好了发送准备,那么在等待的过程中,它会如何处理发送往给定目的地的多个报文?
产生结果是令人吃惊的,首先在第一个ARP应答返回之前,产生了六个ARP请求,其原因是 IP很快产生了六个IP数据报片,而每个数据报片生成了一个 ARP请求。
第二,在收到第一个 ARP应答 的时候,只将最后一个 IP数据报片 发送给目的端。
这种情况,称为 ARP洪泛。即以 高速率重复 发送到 同一个IP地址 的 ARP请求。
ARP 应该保留至少一个报文,而这个报文必须是最后一个报文。
当第一个到达的数据报片 出现的时候,目的端 IP层 必须启动一个计时器,值为30s或者60s,如果超时,且所有数据报片没有全部到达(没有出现 MF = 0 的数据报片),则将这些报片全部丢弃。否则会引起接收端缓存满。
如果按照上面的情况丢弃数据报,没有ICMP消息的产生。这是因为 并未接收到 包含UDP首部的 偏移量为0 的第一个数据报片(注意区别 第一个 和 第一个到达的),除非接收到,否则不要求产生任何ICMP报文。
这样的话,上层:TCP或者UDP的应用程序,最终会超时重传。
11.10 最大UDP数据报长度
UDP数据报 中用户数据的最大长度:65507字节。
限制因素:
- 应用程序受到其端口的限制。
- TCP/IP 内核实现,导致实现特性(或者差错),使IP数据报 小于65535字节。
数据报截断
IP能够发送或者接收特定长度的数据报,并不意味着,接收应用程序也可以读取该长度的数据。
UDP 接口允许应用程序指定每次返回的最大字节数。但是 如何解决 接收到 的数据报长度 大于 应用程序所能处理的长度?取决于 编程接口和实现。
11.11 ICMP源站抑制错误
使用UDP 可以产生 ICMP 源站抑制 错误。
当一个接收端(系统) 接收数据报的速度 >>(远大于) 处理速度 的时候,缓存很容易用完。这个时候就 可能 产生这个错误 (注意可能,即使缓存已满丢弃了部分数据报,也并不要求这样做):
别再发送啦,我快受不了了!!
11.12 UDP服务器的设计
客户端的设计和实现 比 服务端的要轻松很多。服务器端需要与操作系统进行交互作用,而且大多数情况下,需要处理多个用户。
服务器启动之后处于休眠状态,等待客户请求的到来。
大多数 UDP服务器,是重复型服务器。(参见第一章)
11.12.1 客户IP地址 及 端口号
来自客户的 是 UDP数据报。IP首部包含源端和目的端IP地址。UDP首部包含了源端和目的端的UDP端口号(用于 分用)。当应用程序接收到 UDP数据报 的时候,操作系统必须告诉它是谁发送的消息(即告诉 源端IP地址 和端口号)。
这个特性允许一个 交互UDP服务器对多个客户进行处理,并发送应答。
11.12.2 目的IP地址
一些应用程序需要知道 数据报 是发送给谁的,即目的IP地址。如果目的IP地址是广播地址,则自动忽略。
这要求操作系统 告诉应用程序 目的IP地址。
11.12.3 UDP输入队列
大多数UDP服务器 是 重复型服务器。这意味着 单个服务器 在 单个UDP端口上 处理 所有的请求。UDP将所有请求自动排队,将以接收顺序传给输入端。UDP输出队列 是 FIFO的(先进先出)。排队溢出造成的数据报丢失是可能存在的。
2016/8/4