UDP是一个很简单的协议,定义它的rfc768只有短短三页。作为一个传输层协议,UDP只在网络层协议如IPV4/IPV6上做了一个简单的扩展。

UDP的Header由四个字段组成,Src Port(2 Bytes), Dest Port(2 Bytes), Checksum(2 Bytes), Length(2 Bytes)。相比于IP协议,UDP增加了:

  • 端口
  • checksum

端口机制使得在同一个IP地址下,可以同时有多个使用UDP的应用互不干扰。Checksum则为数据提供了简单的错误发现机制。

值得注意的是,Checksum计算的时候,在UDP的Header和包内容之前,还额外的包含了IP的Pseudo Header,里面主要包含了IP Header中的Src Addr, Dest Addr, Protocal Number和Data Length等信息。 这是因为包的接收方需要验证包的源地址和包的目标地址,在网络传输的过程中,没有发生损坏,以确保未受到期望之外的数据包。由于上层的协议需要依赖于下层的数据,这是一种违反分层的做法(Layer Violation)。 IPV4 Header中,本身就包含了Checksum,UDP的Checksum尽管被推荐使用,在性能敏感的情况下,用户也可以将UDP的Checksum设置成0来关闭校验。IPV6的header中没有Checksum,因此使用IPV6协议的UDP包,必须包括Checksum。

考虑到在某些场景下,可能只需要对UDP内容的一部分数据进行校验,所以产生了UDP Lite协议。 UDP lite协议去掉了多余的Length字段(UDP Length可以通过IP的Length减去IP头的长度算出来),加入了checksum coverage字段,来设置需要Checksum的数据长度。

UDP由于无连接的特性,适合需要Broadcast或Multicast的场景。

在UDP的使用中,应额外关注IP Fragmentation。UDP没有自动的措施防止Fragmentation。 网络中各段的MTU是不一样的,假设UDP的包+IP header超过了某段链路MTU,如果IP的DF(Don't Fragment)字段没有设置,UDP就可能被分成若干个IP Fragment发送。 先到的Fragment会被接收方缓存,经过一段超时(通常为30s或者60s)后,如果全部的fragment还没有到达,buffer中的数据会被完全丢弃,并(可能)向发送方发送一条ICMP消息,告知包内容已被丢弃。 如果这些Fragment中有任意一个在传输过程中丢失或错误传输,因为UDP没有重传和纠错机制,这个UDP包会被整体丢弃,影响网络性能。 尽管UDP本身支持2^16 - 1 = 65535字节大小的长度,但大部分的UDP包设置在1500 Bytes以下,以避免分片。1500 Bytes这个边界,是因使用广泛的Ethernet限制的。

在IP的DF字段设置的时候,经过支持PMTUUD(Path MTU Unit Discovery)的路由的时候,路由会丢弃超过MTU大小的包,并回传一条ICMP消息,告诉发送方当前路径的MTU。 如果发送方接受到这条ICMP消息,会根据消息内容记录MTU,并调整UDP包的大小。

UDP使用简单方便,开销小,适合对性能要求高,数据准确性要求较低的场景使用,如流媒体,视频等。但缺乏重传,Congestion Control,Flow Control等机制,需要上层应用自己实现。