UDP 是一个简单地面向数据报的运输层协议:进程的每个输出操作都正好产生一个 UDP 数据报,并组装成一份待发送的 IP 数据报。
UDP 不提供可靠性,它把应用程序传给 IP 层的数据发送出去,但是并不保证他们能到达目的地。
UDP 首部
UDP 首部格式:16位源端口号,16位目的端口号,16位 UDP 长度,16位 UDP 检验和,如果有数据后面接着数据。端口号表示发送进程和接收进程,UDP 长度字段指的是 UDP 首部和 UDP 数据的字节长度。
UDP 检验和
UDP 检验和覆盖 UDP 首部和 UDP 数据,而 IP 首部的检验和,只覆盖 IP 的首部。UDP 的检验和是可选的,TCP的检验和是必须的。
UDP 数据报为了计算检验和而设置的12字节长的伪首部。伪首部的格式为:32位源 IP 地址,32位目的 IP 地址,0,8位协议,16位 UDP长度。伪首部中包含 IP 首部一些字段,其目的是让 UDP 两次检查数据是否已经正确到达目的地。
如果发送端没有计算检验和而接收端检测到检验和有差错,那么 UDP 数据报就要被悄悄的丢弃。
UDP 检验和是一个端到端的检验和,它由发送端计算,然后由接收端验证,其目的是为了发现 UDP 首部和数据在发送端和接收端之间发生的任何改动。
IP 分片
物理网络层一般要限制每次发送数据帧的最大长度,任何时候 IP 层接收到一份要发送的 IP 数据报时,他要判断向本地那个接口发送数据(选路),并查询该接口获得其 MTU。IP 把 MTU 与数据报长度进行比较,如果需要则进行分片。分片可以发生在原始发送端主机上,也可以发生在中间路由上。
把 一份 IP 数据报分片以后,只有到达目的地才进行重新组装,重新组装由目的端的 IP 层来完成,其目的是使分片和重新组装过程对运输层是透明的。
传输 IP 分片数据时,即使丢失一片数据也要重传整个数据报,因为 IP 层本身没有超时重传的机制,而是由 TCP 重新发送整个 TCP 报文段,该报文段对应于一份 IP 数据报。所以 TCP 避免分片,但使用 UDP 很容易导致 IP 分片。
注意:IP 数据报是指 IP 层端到端的传输单元(在分片之前和重新组装之后),分组是指在 IP 层和链路层之间传送的数据单元。一个分组可以使一个完整的 IP 数据报,也可以是 IP 数据报的一个分片。
ICMP 不可达差错
发生 ICMP 不可达差错的另一种情况是,当路由器收到一份需要分片的数据报,而在 IP 首部又设置了不分片(DF)的标志比特。
需要分片但又设置不分片标志比特时的 ICMP 不可达差错报文格式:
类型、代码、检验和、0、下一站网络的 MTU、IP 首部+原始 IP 数据报中数据的前8字节
用 Traceroute 确定路径 MTU
通过发送分组,并设置“不分片”标志比特,发送的第一个分组的长度正好与出口 MTU 相等,每次收到 ICMP “不能分片”差错时,就减小分组的长度。如果路由器发送的 ICMP 差错报文是新格式,包含出口 MTU,那么就用该 MTU 值来发送,否则就用下一个最小的 MTU 值来发送。
UDP 服务器的设计
客户 IP 地址及端口号
来自客户的 UDP 数据报,IP 首部包含源端和目的端 IP 地址,UDP 首部包含了源端和目的端的 UDP 端口号。这一特性允许一个交互 UDP 服务器对多个客户进行处理。
目的 IP 地址
一些应用程序需要知道数据报是发送给谁的,即目的 IP 地址。这要求操作系统从接收到的 UDP 数据报中将目的 IP 地址交给应用程序,但是并非所有的实现都提供这个功能。
UDP 输入队列
通常程序所使用的每个 UDP 端口都与一个有限大小的输入队列相联系,即来自不同客户的差不多同时到达的请求将由 UDP 自动排队。但是,排队溢出造成内核中的 UDP 模块丢弃数据报的可能性是存在的。
限制本地 IP 地址
大多数 UDP 服务器在创建 UDP 端点时都使其本地 IP 地址具有通配符的特点,这就表明进入 UDP 数据报如果其目的地为服务器端口,那么在任何本地接口均可接收到它。
当服务器创建端点时,他可以把其中一个主机本地 IP 地址包括广播地址指定为端点的本地 IP 地址,只有当目的 IP 地址与指定的地址相匹配时,进入的 UDP 数据报才能被送到这个端点。
有可能在相同的端口上启动不同的服务器,每个服务器具有不同的本地 IP 地址,但是,一般必须告诉系统应用程序重用相同的端口号没问题,在 sock 程序中是通过 -A 选项来完成的。
限制远端 IP 地址
UDP 服务器本身可以创建三类地址绑定:
本地地址 | 远端地址 | 描述 |
---|---|---|
localIP.Iport | foreignIP.fport | 只限一个客户 |
localIP.Iport | *.* | 限于到达一个本地接口的数据报:localIP |
*.Iport | *.* | 接收发送到 Iport 的所有数据报 |
Iport 指的是服务器有名端口号,localIP 必须是本地接口的 IP 地址。表中这三行的排序是 UDP 模块在判断用哪个端点接收数据报时所采用的顺序。