UDP(用户数据报协议)

引言

UDP是一个简单地面向数据报的传输层协议:进程的每个输出操作正好产生一个UDP数据报,并组装成一份待发送的IP数据报。这与面向流字符的协议不同,如TCP,应用程序产生的全体数据与真正发送的单个IP数据报可能没有什么联系。
UDP数据报封装成一份IP数据报,如下图所示。

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

UDP首部

UDP首部的各字段如下图所示。

端口号表示发送进程和接收进程。
UDP长度字段指的是UDP首部和UDP数据的字节长度。该字段的最小值为8字节(发送一份0字节的UDP数据报是ok的)。
UDP校验和,UDP和TCP在首部中都有覆盖它们首部和数据的检验和。UDP的检验和是可选的,而TCP的检验和是必需的。UDP的数据报的长度可以为奇数字节,但是检验和算法是把若干个16bit字相加。解决方法是必要时在最后增加填充字节0,这只是为了检验和的计算(也就是说,可能增加的填充字节不被传送)。其次,UDP数据报和TCP段都包括一个12字节长的伪首部,它是为了计算检验和而设置的。UDP校验和是一个端到端的校验和。它由发送端计算,然后由接收端验证。其目的是为了发现UDP首部和数据在发送端到接收端之间发生的任何改动。不要完全相信数据链路(如以太网,令牌环等)的CRC检验,应该始终打开端到端的检验和功能。而且如果你的数据很有价值,也不要完全相信UDP和TCP的校验和,因为这些都是简单地检验和,不能检测出所有可能发生的差错。

UDP服务器的设计

客户IP地址及端口号

来自客户的事UDP数据报。IP首部包含源端和目的端IP地址,UDP首部包含了源端和目的端的UDP端口号。
这个特性允许一个交互UDP服务器对多个客户进行处理。给每个发送请求的客户端发回应答。

目的IP地址

一些应用程序需要知道数据报是发送给谁的,这要求操作系统从接收到的UDP数据报中将目的IP地址交给应用程序。不幸的是,并所有的操作系统都提供这个功能。

UDP输入队列

通常程序所使用的每个UDP端口都与一个有限大小的输入队列相联系。这意味着,来自不同客户的差不多同时到达的请求将由UDP自动排队。接收到的UDP数据报以其接收顺序交给应用程序(在应用程序要求交送下一个数据报时)。然而,排队溢出造成内核中的UDP模块丢弃数据报的可能性是存在的。

限制本地IP地址

大多数UDP服务器在创建UDP端点时都使其本地IP地址具有通配符(wildcard)的特点。这就表明进入的UDP数据报如果其目的地为服务器端口,那么在任何本地接口均可接受到它。
当服务器创建端点时,它可以把其中一个主机本地IP地址包括广播地址指定为端点的本地IP地址。只有当目的IP地址与指定的地址相匹配时,进入的UDP数据报才能被送达这个端点。
有可能在相同的端口上启动不同的服务器,每个服务器具有不同的本地IP地址。但是,一般必须告诉系统应用程序重用相同的端口是没问题的。使用socket API时,必须指定SO_REUSEADDR选项。

限制远端IP地址

大多数系统允许UDP端点对远端地址进行限制。这说明端点将只能接收特定IP地址和端口号的UDP数据报。

每个端口有多个接收者

大多数的系统在某一时刻只允许一个程序端点与某个本地IP地址及UDP端口号关联。
在一个支持多播的系统上,这种情况将发生变化。多个端点可以使用同一个IP地址和UDP端口号,尽管应用程序通常必须告诉API是可行的。使用socket API时,必须指定SO_REUSEADDR选项。当UDP数据报到达目的IP地址为多播地址或广播地址,而且目的IP地址和端口号处有多个端点时,就向每个端点传送一份数据报的复制。但是如果UDP数据报到达的是一个单播地址,那么只向其中一个端点传送一份数据报的复制。选择哪个端点传送数据取决于各个不同的系统实现。