文章目录
- UDP 协议
- 1. UDP协议报文结构
- 1.1 一个 UDP 数据报能传输的最大数据
- 1.2 校验和
- 1.3 生成校验和的算法
UDP 协议
1. UDP协议报文结构
16位UDP长度,表示整个数据报(UDP首部+UDP数据)的最大长度,如果校验和出错,就会直接丢弃。
上述的这张图是任何一个计算机网络教科书上都会有的,而且都是这么画的。
但是实际上这么画的不够严谨。(为了排版方便,变形了)
更严谨的是下面的这张图。
在通过 UDP socket (也就是 send 方法拿来的数据)的基础上,在前面拼装上几个字节的报头。
(这里的拼接相当于字符串拼接,只不过此处的是二进制的,不是文本的)
UDP 报头里包含了一些携带了重要信息的特定属性,不同的协议,功能不同,报头中带有的属性信息就不同。
对于 UDP 来说,报头一共就是 8 个字节,分成 4 个部分(每个部分 2 个字节)
1.1 一个 UDP 数据报能传输的最大数据
UDP 报文长度也是 2 个字节表示的,2 个字节表示的范围是 0 ~ 655635,换算单位是64KB。
也就是说,一个 UDP 数据报最大只能传输 64KB 的数据。
这个 64KB 的大小当然是非常小的,因为随便拍一张照片都是好几个 MB 的大小。
这个时候如果应用层数据报超过了 64KB 怎么办?
这里涉及到两种解决的办法。
1、需要在应用层里,通过代码的方式针对应用层数据报进行手动的分包,拆分成多个包,通过多个 UDP 数据报进行传输。
(也就是说,本来只需要 send 一次,现在需要 send 多次了)
这就好比,搬家的时候由于家具比较多,一辆车装不下,就会多叫几辆。
但是这里会多出更多的像约车,装车,卸货等一些过程,所以会比较麻烦。
2、不使用 UDP 改为 TCP (TCP 没有这样的限制)
就好比搬家的时候,一次叫一辆大点的货车,一次运输完成。
哪种方案更好?
如果使用的是第一种方案,就需要写很多的代码,还需要进行很多的测试和处理很多的 bug。
这个时候,工作量就变多了,工作时间就变成长了,幸福程度也就变低了。
所以更推荐第二种使用 TCP 的方案。
1.2 校验和
校验和的作用是验证传输的数据是否是正确的
在网络传输的过程中可能会受到一些干扰,在这些干扰下就可能会出现 “比特翻转” 的情况。
也就是 二进制位的 1 变为 0,0 变为了 1。
网络传输的本质上就是光信号/电信号,这些可能会受到一些物理环境的影响,比如电场、磁场、高能射线。
如果一个数据是 1111 0000,出现了 “比特翻转” 后就会变成 0000 1111。而一旦数据改变了,对于数据的含义可能就是致命的。
如果某个程序中经常使用 1 表示某个功能开启,0 表示关闭,本来网络数据报是想开启功能,结果翻转后,导致变成了关闭了。
这样的现象是客观存在的,是不可避免的,能做的就是及时识别出当前的数据是否有问题。
因此就引入了校验和来进行鉴别。
校验和会针对数据的内容进行一系列的数学运算,得到一个比较短的结果(比如 2 字节)
如果数据的内容一定,得到的校验和结果就一定;如果数据改变了,得到的校验和也就变了。
举一个例子,想有一个发送方和一个接收方,发送方要向接收方发送一条 hello 的数据。
接收方得到数据后需要重新计算一遍校验和,看看得到的结果和发送方发来的结果是不是一样的。
如果一样,说明数据传输没问题,如果不一样,说明数据已经出错。
如果数据内容一定,按照同样的算法得到的校验和也是 0xaabb。
如果数据出错了,接收方得到的数据是我草,那么此时重新计算校验和就会与得到的校验和不一样。
接收方得到的校验和是 0xaabb,重新计算校验和得到的可能是 0xbbaa,此时说明数据传输就出错了。
值得注意的地方
如果内容相同,得到的校验和一定相同;校验和相同,原始内容不一定相同。(存在小概率时间)
但是在实际的工程实践中,这种情况忽略不记了,一般认为,校验和相同,原始内容也想同。
因为毕竟 计算得到的校验和和之前得到的校验和一样 的情况出现的概率极低,也就忽略不记了。
比方说发送 hello 的校验和是 0xaabb,而发送 我草 的校验和也是 0xaabb。(好像不太可能会出现这种情况)
校验和一般会和内容挂钩,基于数据内容算出来的校验和,只要内容一变,就能够及时发现。
比如张三去买菜,一共要买 鸡蛋、西红柿、黄瓜、小葱这四种。
一共四样,这实际上也是一个校验和,可以随时根据这四个字来验证当前买菜的状态,但这不是一个基于内容的校验和。
如果张三买的时候有一样买错了,虽然内容不一样了,但是一共还是四样,是无法及时发现的。
1.3 生成校验和的算法
针对网络传输的数据来说,生成校验和的算法有很多种,下面介绍几个比较知名的:
1、CRC:循环冗余校验
比较简单粗暴,把数据上的每个字节循环往上累加。如果累加溢出了,高位就不要了。
这种算法虽然比较好算,但是校验结果不是特别理想。
万一数据同时变动了两个比特位。(前一个字节少1,后一个字节多1这种),就会出现内容变了, 但是 CRC 没变这样的情况。
2、MD5 不是简单相加,有一系列的公式来进行更复杂的数学运算。
MD5 算法特点:
1、定长。无论原始数据多长,得到 MD5 长度都是固定长度(有4字节版本,也有8字节版本)
2、冲突概率很小。原始数据哪怕只变动一个地方,算出来 MD5 值都会差别很大。(让 MD5 结果更分散了)
3、不可逆。通过原始数据计算 MD5 很容易,通过 MD5 还原原始数据(找到哪个数据生成了这个 MD5的)很难。
3、SHA1 和 MD5 的思路是非常相似的。