We read the world wrong but say that it deceives us.编程
"咱们看错了世界,却说世界欺骗了咱们"缓存
参考资料:TCP/IP入门经典 (第五版)服务器
1、简介socket
UDP(User Datagram Protocol,用户数据报协议),是一个简单的面向数据报的传输层协议,进程的每一个输出操做都正好产生一个UDP数据报,并组装成一份待发送的IP数据报。它在协议栈中的位置以下函数
特色:UDP是一个面向数据报的协议,因此它不提供可靠性:它把应用程序传给IP层的数据发送出去,但并不保证它们能到达目的地spa
2、UDP首部设计
因为不提供可靠性,因此UDP的首部比较简单blog
各字段含义以下:接口
● 端口号:就是传输层识别应用程序的一个正整数
● 16位UDP长度:UDP长度指的是UDP首部和UDP数据的总长度。注意,UDP长度的最小值为8字节,也就是说能够发送一个没有数据的UDP数据报。记得在 TCP/IP协议-IP协议 中说到IP首部中有一个首部长度,那么用IP数据报的总长减去IP首部的长度就能够获得UDP数据报的长度了
● 16位UDP检验和:关于检验和,要特别留意几点。
首先,UDP的检验和覆盖了UDP首部和UDP数据,而IP首部的检验和只覆盖了IP首部;其次,UDP的检验和是可选的,而TCP的检验和是必须的;UDP数据报的长度能够是奇数字节,因此在计算时要在末尾填充0,可是这些0可能不被传送;UDP检验和的计算方法与IP首部的检验和同样(16个bit的二进制反码求和)
最后,UDP在计算检验和的时候包含了一个12字节长的伪首部,它仅仅是为了计算检验和而设置。UDP检验和计算过程当中使用的各个字段以下
若是检验和的计算结果为0,则存入的值全为1。若是传送的检验和为0,说明发送端没有计算检验和。这样,若是接收端计算的检验和不为全0,可是检验和字段为全0的话,说明传送过程当中出错了,UDP数据报将会被丢弃,而且不产生任何差错报文
虽然UDP检验和是可选的,可是它们应该老是在用,毕竟仍是要确报数据传输的正确性
3、IP分片和重组
为何要在这里讨论IP分片呢?前面讲到UDP是不提供传输的可靠性的,可是至少要保证数据能完整的传输,因此只能把这个责任留给IP。下面先来了解几个概念
最大UDP数据报长度
IP数据报的最大长度为65535个字节,去掉IP首部的20个字节和UDP首部的8个字节,UDP数据报的最大长度理论上应该为65507字节。但事实上,大多数实现都达不到这个长度,缘由有下:
● 应用程序接口限制:socket API提供了一个可供应用程序调用的函数,用来设置接收和发送缓存的长度,大部分系统都默认提供了可读写大于8192字节的UDP数据报。
● 内核实现:可能存在一些实现特性(或差错),使IP数据报长度小于65535
虽然IP能够发送那么长的数据报,但应用程序并不保证可以读取该长度的数据。所以,UDP编程接口容许应用程序设置能处理的最大长度。当数据报长度超出应用程序能处理的最大长度时,不一样的API有着不一样的处理策略,这就要求发送端控制数据报的大小
路径MTU
MTU(最大传输单元),指的是数据链路层对传输的数据帧长度的一个上限值,不一样的网络类型有着不一样的值。而路径MTU指的是两台通讯主机路径中最小的MTU。两台主机之间的路径MTU不必定是一个常数,由于路由选择并不必定是对称的,并且网络随时都在发生变化
ICMP
ICMP(Internet控制报文协议),是一个位于网络层的协议。它常常被认为是IP层的一个组成部分,由于ICMP的主要功能是传递差错报文及其余须要注意的信息,而且ICMP报文是封装在IP数据报内部的
常见的几种差错报文:
● 端口不可达:若是接收端收到一份UDP数据报而目的端口与某个正在使用的进程不相符,那么UDP返回一个ICMP不可达报文
● 分片冲突不可达:当路由器收到一份须要分片的数据报,而在IP首部又设置了不分片的标志位,那么路由器返回一个ICMP不可达报文。而且,此时能够把这条路径的路径MTU返回给源主机或路由器,这样就能够帮助这条路径上的其余路由器肯定每一个子路径上的MTU,这被称做路径MTU发现机制
● 源站抑制:当一个系统(路由器或主机)接收数据报的速度比其处理速度快时,它有可能会返回一个源站抑制差错报文。因为源站抑制须要消耗带宽,而且实际上没有什么做用,因此人们并不支持产生源站抑制报文
IP分片
前面已经讲过,数据链路层通常要限制每次发送数据帧的最大长度(MTU)。任什么时候候IP层接收到一份要发送的IP数据报时,它要判断向本地哪一个接口发送数据(选路),并查询接口得到MTU,若是数据报长度大于MTU,那就须要进行分片。分片能够发生在原始发送端主机上,也能够发生在中间路由器上。
在介绍IP首部字段的时候,谈到IP首部的“第二行”有三个字段:16位标识、3位标志和13位片偏移,它们就是被用在IP分片过程当中。对于发送端发送的每份IP数据报来讲,其标识字段都包含一个惟一值,在数据报分片时被复制到每一个片中,代表它们是来自同一个数据报。标志字段用其中一个bit来表示“更多的片”,把该位置1表示这个还有其余分片,因此最后一片要把该位置0。片偏移字段指的是该片偏移原始数据报开始处的位置。另外,分片之后,每一个片的总长度值要改成该片的长度值。标志字段中有一个bit称做“不分片”位,若是将这个置1,IP将不对数据报进行分片。若是此时致使数据报不能发送,那么将会返回一个ICMP不可达差错报文(分片冲突)
分片以后,每一片都成为一个分组,这里的分组指的是网络层到数据链路层之间的传输单元,而IP数据报是指IP层端到端的传输单元。每一个分组都有本身的IP首部
须要注意是:
● 在分片时,除最后一个片外,其余每个片中的数据部分(除IP首部外的其他部分)必须是8字节的整数倍(暂时没搞清楚为何,我的猜想是为了方便计算片偏移,还有接收端的重组)
● 任何传输层首部只出如今第一片数据中
● 分片可能发生在源主机或者路径上的路由器,但重组只可能发生在目的主机上。由于路径上的路由器只负责转发,并不关心IP数据报的数据内容
● 即便只丢失了一片数据也须要从新传整个数据报,由于上一点,中间路由器可能再次分片,而目的端并不知道丢失的片是被如何分片的
● 各个片到达目的端时多是乱序的,可是IP首部利用前面讲的三个字段,能够将分片正确地拼接起来
下面来完整描述一个IP数据报的传输过程做为总结,假设待发送的传输层数据报须要进行分片,而且发送端和接收端不是直接相连:
①源主机的传输层将数据报发送到网络层;
分片:②
②IP发现数据报太大,须要分片,就将数据报分片:第一片包含了数据报的开头部分数据,数据大小为8字节的整数倍,包含了传输层首部,并将标志字段中表示“更多的片”字段置1,片偏移字段置0,而后把总长度值改成分片之后的片长度值;第二片到倒数第二片包含了某个长度的数据,而且数据大小为8字节的整数倍,可是它们都没有包含传输层首部,它们的“更多的片”字段置为1,片偏移字段根据片序号和前一片的数据长度设置,总长度设置同第一片;最后一片包含了剩余的数据部分,数据长度不必定是8字节的整数倍,没有包含传输层首部,“更多的片”字段被置0,片偏移字段根据前面的数据长度设置,总长度值也根据前面的片进行设置;全部片的标识字段都相同
③网络层把每个片做为一个分组传送给数据链路层;
传输:④~⑥
④数据链路层将分组转化为数据帧发送给下一个系统(路由器或者主机);
⑤接收到数据帧的路由器向上传送至网络层;
⑥IP检查数据报长度和MTU,若是须要分片,就跳到第②步;若是不须要分片,就跳到第④步,直到发送到目的主机;
重组:⑦
⑦目的主机陆续收到各个片,若是目的主机发现缺失了某个片,那么将会返回一个ICMP错误报文,源主机将会从新发送数据报,回到第①步;若是没有片缺失,目的主机将会根据标识字段、标志字段和片偏移将全部片重组为传输层数据报,传输层发送给应用程序,数据传输完成
关于IP分片重组的实现,能够参考 Linux TCP/IP协议栈关于IP分片重组的实现
4、UDP服务器设计
最后来讨论一下UDP那些影响使用该协议的服务器的设计和实现方面的协议特性
客户IP地址及端口号
UDP服务器必须保存来自客户数据报的源IP地址和源端口号,这个特性容许一个交互UDP服务器对多个客户进行处理
目的IP地址
某些应用程序须要知道数据报是发送给谁的,即目的IP地址
UDP输入队列
大多数UDP服务器是重复型服务器,单个服务器进程对单个UDP端口上的全部客户请求进行处理。因此必须维护一个输入队列来对差很少同时到达的请求进行处理
限制本地IP地址
大多数UDP服务器在建立UDP端点是都使其IP地址具备通配符的特色,这样能够从任何的本地接口来接收用户请求
限制远端IP地址
限制远端IP地址和端口号能够只接收特定地址的UDP数据报
每一个端口有多个接收者
当UDP数据报到达目的IP地址为广播或多播地址,并且在目的IP地址和端口号处有多个端点时,就向每一个端点传送一份数据报的复制。若是UDP数据报到达的是一个单播地址,那么只向其中一个端点传送一份数据报的复制
总结:UDP是一个简单的协议,本文大部分篇幅都在介绍IP分片的内容,等到介绍TCP的时候,就能了解UDP与TCP之间的区别和联系