UDP报头分成4个部分,每个部分2个字节。分别是:
因为UDP报文长度只有两个字节,表示的范围是0 ~ 65535,0 ~ 65535表示报文长度为0~65535字节(即UDP数据报最大为64kb,口头上说UDP能携带的最大数据是64kb,实际上UDP能携带的最大数据是64kb-8字节(65535-8字节,因为前8个字节是报头不携带数据),但工程上这8个字节可以忽略不计仍然说UDP能携带的最大数据是64kb),64kb的空间很小,所以使用UDP难以表示一个很大的数据报。
当网络通信交互的数据很大时,可以想到两种解决方案:(1)把数据拆分成多个包,使用多个UDP数据包进行传输。但这个方案缺点很大,因为开发成本、测试成本太高(因为要考虑怎样去拆包、怎样去组包、组包时的包的顺序不对怎么办、组包时的包出现缺失出现错误怎么办……) (2)使用TCP,因为TCP没有包大小限制。
那程序员能否对UDP报文长度进行升级,比如2个字节变为4个字节,那使用UDP难以表示一个很大的数据报的问题不就解决了吗?答案是不可以,因为升级要通信双方都要升级,这样双方的数据才能对应得上才能进行通信,换言之全世界的设备都得一起升级,而且升级的是操作系统内核(UDP是内核中实现的),这很难完全协调去进行升级。除非有一个全新的协议把UDP彻底替换掉。
校验和:网络传输中由于一些外部干扰可能会出现数据传输出错的情况(比如磁场电场等干扰光/电信号使某个地方原来是低电平传输变为高电平传输(比特翻转))。因此需要有办法识别出出错的数据,校验和就是这样的一种检查手段。
校验和本质上是一个字符串,体积比原始的数据更小,由原始数据生成。原始数据相同得到的校验和就一定相同,校验和相同原始数据大概率相同(理论上会出现不同的情况,但这个概率非常低可以忽略不计)。
基于校验和完成数据校验:(1)发送方把要发送的数据data1通过一定的算法计算出校验和checksum1。(2)发送方把data1和checksum1一起通过网络发送出去。(3)接收方收到数据data2(data2可能和data1不一样)和checksum1。(4)接收方再根据data2按照同样的算法重新计算校验和得到checksum2。(5)对比checksum1和checksum2是否相同不同则认为data2和data1一定不相同。相同则认为data2和data1大概率相同(理论上存在不同的可能性,但概率很低可以忽略不计)。
计算校验和有很多种算法:UDP中使用的是CRC算法(循环冗余算法)。
循环冗余算法:把当前要计算校验和的数据的每个字节都进行累加保存到2个字节的UDP校验和中去。如果中间某个数据出现传输错误,第二次计算的校验和就会和第一次不同。
CRC算法不是特别靠谱,因为两个不同的数据得到相同的CRC校验和的概率比较大,比如传过来的数据少了一个字节的同时又多了一个字节导致计算出来的校验码和之前的校验码依然相同。
此外还有md5/sha1算法(md5和sha1的特点非常类似,下面介绍md5算法的特点)。
(1)定长。无论原始数据多长,计算出来的mad5校验码的长度都是固定的。这个特点让mad5非常适合用于做校验和,因为校验和本身不应该很长不然不方便网络传输。
(2)分散。两个原始数据哪怕绝大部分都一样,只要其中一个字节不同,得到的md5校验码都会差异很大。这让md5算法也非常适合作为哈希算法,因为哈希表把一个key通过hash函数转换成数组下标,希望hash函数计算出来的结果尽可能分散这样产生hash冲突的概率才会比较小。
(3)不可逆。给定一个原始数据,计算md5校验和容易,但通过md5校验和还原出原始数据很难。因此md5算法也可以应用在一些密码学场景中。
有一些应用层协议是基于UDP来实现的(比如DNS:域名解析协议),但这部分协议不算很多,相比于UDP,TCP在更多情况下更具有优势很多时候会优先考虑使用TCP。