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

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

一个UDP首部是8字节长
端口号表示发送进程和接收进程,TCP端口号与UDP端口号是相互独立的。(不过有时候TCP和UDP同时提供某种致命服务的时候,两种协议通常选择相同的端口号,纯粹是为了方便。)
UDP长度字段指的是UDP首部和UDP数据报的字节长度,该长度最小值为8字节(发送一分0字节的UDP数据报是OK),这个UDP长度是有冗余的。
IP数据报长度指的是数据报全长,因此UDP数据报长度是全长减去IP首部的长度
UDP检验和
UDP检验和是一个端到端的检验和,它由发送端计算,然后由接收端验证,其目的是为了发现UDP首部和数据在发送端到接收端之间发生的任何改动。
UDP检验和覆盖UDP首部和UDP数据。而IP首部的检验和,它只覆盖IP的首部—并不覆盖IP数据报中的任何数据。
UDP和TCP在首部中都有覆盖它们首部和数据的检验和,UDP的检验和是可选的,而TCP的检验和是必需的。
UDP检验和的计算方法与IP首部检验和计算法法类似,但也有不同
1、UDP数据报的长度可以为奇数字节,但是检验和算法是把若干个16bit字节相加。解决方式是必要时在最后增加填充字节0,这只是为了检验和的计算
2、UDP和TCP段都包含一个12字节长的伪首部,它是为了计算检验和而设置的。
伪首部包含IP首部一些字段。其目的是让UDP两次检查数据报是否已经正确到达目的地。

注意:UDP数据报的长度在检验和计算过程中出现了2次
如果检验和的计算结果为0,则存入的值为全1(65535),这在二进制反码计算中是等效的,如果传送的检验和为0,说明发送端没有计算检验和。
如果发送端没有计算检验和而接收端检测到检验和有差错,那么UDP数据报就要被悄悄地丢弃,不产生任何差错报文(当IP层检测到IP首部检验和有差错时也这样做)
利用tcpdump可以得知系统是否打开了UDP检验和选项

IP分片
物理网络层一般都要限制每次发送数据帧的最大长度,任何时候IP层接收到一份要发送的IP数据报时,它要判断向本地哪个接口发送数据(选路),并查询该接口获得其MTU,IP把MTU与数据报长度进行比较。如果需要则进行分片,分片可以发生在原始发送端主机上,也可以发生在中间路由器上。
把一份IP数据报分片后,只有到达目的地才进行重新组装。
重新组装由目的端的IP层来完成,其目的是使分片和重新组装过程对运输层(TCP、UDP)是透明的。
对于发送端发送的每份IP数据报来说:
其标识字段都包含一个唯一值。该值在数据报分片时被复制到每个片中。
标志字段用其中一个比特来表示“更多的片”,除最后一片外,其他每个组成数据报的片都要把该比特置1
片偏移字段指的是该片偏移原始数据报开始处的位置。
当数据报被分片后,每个片的总长度值要改为该片的长度值
最后,标志字段中有一个比特称作“不分片”位,如果将这一比特置1,IP将不对数据报进行分片。相反把数据报丢弃并发送一个ICMP差错报文(“需要进行分片但设置了不分片比特”)给起始端。
当IP数据报被分片后,每一片都称为一个分组,具有自己的IP首部,并在选择路由时与其他分组独立。这样,当数据报的这些片到达目的端时有可能会失序,但是在IP首部中有足够的信息让接收端能正确组装这些数据报片

举个例子:
利用sock程序来增加数据报的长度,直到分片发生
在一个以太网上,数据帧的最大长度是1500字节,假设IP首部20字节,UDP首部8字节,我们分别以数据长度为1471,1472,1473,1474字节运行sock程序,那么最后两次应该发生分片:

tcpdump输出如下:

tcpdump打印出的信息:
frag26304(第3行和第4行)和frag 26313(第5行和第6行)指的是IP首部中标识字段的值
第三行中位于冒号和@号之间的1480,是除IP首部外的片长。两份数据报第一片的长度均为1480,第一份数据报的第二片长度为1,第二份的第二片长度为2
在分片时,除最后一片外,其他每一片中的数据部分(除IP首部外的其余部分)必须是8字节的整数倍。
位于@符号后的数字是从数据报开始处计算的片偏移值。两份数据报第1片的偏移值均为0(第3行和第5行),第2片的偏移值为1480(第4行和第6行)
跟在偏移值后面的加号对应IP首部中3bit标志字段中的“更多片”比特,设置这一比特的目的是让接收端知道在什么时候完成所有的分片组装。
需要注意:任何运输层的首部只出现在第一片数据中
分片情况:

ICMP不可达差错(需要分片)
发生ICMP不可达差错的另一种情况是,当路由器受到一份需要分片的数据报,而在IP首部又设置了不分片(DF)的标志比特。
这个差错可以用来判断到达目的端路途中最小MTU是多少,也称其为路径MTU发现机制。
ICMP不可达差错报文格式:

如果路由器没有提供这种新的ICMP差错报文格式,那么下一站的MTU就设为0
UDP和ARP之间的交互作用
我们使用IP数据报片来查看UDP和ARP之间的交互作用
如果发送端迅速发送多个UDP数据报,也可以看到这个交互过程。我们采用分片的方法,是因为IP可以生成报文的速度,比一个用户进程生成多个数据报的速度更快。
NFS发送的UDP数据报长度超过8192字节。
在以太网上,这些数据报以我们所指出的方式进行分片,如果适当的ARP缓存入口发生超时,那么就可以看到这里所显示的现象,NFS将超时并重传,但是由于ARP的有限队列,第一个IP数据报仍可能被丢弃。
最大UDP数据报长度
理论上,IP数据报的最大长度是65535字节,这是IP首部16比特总长度字段所限制的。
去除20字节的IP首部和8个字节的UDP首部,UDP数据报中用户数据的最大长度为65507字节,但是,大多数实现所提供的长度比这个最大值小。
两个限制因素:
1、应用程序可能会受到其程序接口的限制。socket API提供了一个可供应用程序调用的函数,以设置接收和发送缓存的长度。对于UDP socket,这个长度与应用程序可以读写的最大UDP数据报的长度直接相关。现在的大部分系统都默认提供了可读写大于8192字节的UDP数据报(使用这个默认值是因为8192是NFS读写用户数据数的默认值)
2、TCP/IP的内核实现。可能存在一些实现特性(或差错),使用IP数据报长度小于65535字节
ICMP源站抑制差错
当一个系统(路由器或主机)接收数据报的速度比其他处理速度快时,可能产生这个差错。
注意“可能”,即使一个系统已没有缓存并丢弃数据报,也不要求它一定要发送源站抑制报文。
UDP服务器的设计
使用UDP的一些蕴含对于设计和实现服务器会产生影响
对于服务器来说,它启动后处于休眠状态,等待客户请求的到来,对于UDP来说,当客户数据报到达时,服务器苏醒过来,数据报中可能包含来自客户的某种形式的请求信息。
客户IP地址及端口号
来自客户的是UDP数据报。IP首部包含源端和目的端IP地址,UDP首部包含了源端和目的端的UDP端口号,当一个应用程序接收到UDP数据报时,操作系统必须告诉它是谁发送了这份消息,即源IP地址和端口号
这个特性允许一个交互UDP服务器对多个客户进行处理。给每个发送请求的客户发回应答。
目的IP地址
一些应用程序知道需要数据报是发送给谁的,即目的IP地址
TFTP服务器必须忽略接收到的发往广播地址的数据报
这要求操作系统从接收到的UDP数据报中将目的IP地址交给应用程序
UDP输入队列
大多数UDP服务器是交互服务器,这意味着,单个服务器进程对单个UDP端口上(服务器上的名知端口)的所有客户请求进行处理。
通常程序所使用的每个UDP端口都与一个有限大小的输入队列相联系。这意味着,来自不同客户的差不多同时到达的请求将由UDP自动排队。接收到的UDP数据报以其接收顺序交给应用程序(在应用程序要求交送下一个数据报时)。
然而,排队溢出造成内核中的UDP模块丢弃数据报的可能性是存在的。
应用程序并不知道其输入队列何时溢出,只是由UDP对超出数据报进行丢弃处理。
没有发回的任何信息告诉客户其数据报被丢弃。这里不存在像ICMP源站抑制这样发回发送端的消息。最后,看来UDP输出对了是FIFO(先进先出)的。而ARP输入确是LIFO(后进先出)的。
限制本地IP地址
大多数UDP服务器在创建UDP端点时都使其本地IP地址具有通配符的特点。这表明进入的UDP数据报如果其目的地址为服务器端口,那么在任何本地接口均可接收到它。
限制远端IP地址
在下面的看不懂了。。等之后在看吧。。
每个端口有多个接收者
大多数的系统在某一时刻只允许一个程序端点与某个本地IP地址及UDP端口号相关联。当目的地位该IP地址及端口号的UDP数据报到达主机时,就复制一份传给该端点。

网友评论