1.端口号
在讲解UDP数据报之前需要先了解一下端口号
端口号是存在于传输层协议的概念
TCP和UDP 数据报中都会包含源端口和目的端口,他们都占有两个字节(16bit)的空间
我们自己写的程序设计端口号一般都是从1024开始的(到65535)
那么1024之前的端口为什么不可以被使用呢?
因为0~1023 这些端口号是分配给了一些知名的广泛使用的应用程序使用的,虽然每个人的设备上面的情况都会有所不同,比如:有点人当前主机上没有运行该程序,或者当前主机上根本就没下载当前的应用,但是为了防患于未然0~1023之间的端口号是不建议使用的.
当然这些端口也不是完全不能用,如果确定当前这些端口没有程序占用,那么使用这些(0~1023)端口也是可以的.
2.UDP协议
UDP协议的特点是:无连接,不可靠传输,面向数据报,全双工.
这些特性在《网络编程》这篇文章中详细说明了
下面我们看一下UDP的报文结构
![](https://i-blog.csdnimg.cn/blog_migrate/ed32ae2e051569e0ba52191ced12e310.png)
上面这张图简单的描绘出来UDP 的报文结构,下面我们进行解析
首先我们知道,UDP数据报分为报头和载荷
UDP会在载荷数据前面加上一个UDP报头,这样就形成了一个完整的UDP数据报
也就是通过UDP socket 里面的send方法,在数据前面加上一个UDP报头(类似于字符串拼接的方式,不过此处是二进制数据,不是文本)
![](https://i-blog.csdnimg.cn/blog_migrate/7a264174a13dafde20a6df2af952bcb5.png)
载荷比较容易理解,里面存储的是应用层数据报
在报头中则会包含一些特定的属性:源端口,目的端口,UDP报文长度,校验和.
如下:
![](https://i-blog.csdnimg.cn/blog_migrate/3b65ee222b4401c33f1b98825f54378f.png)
这四个属性各自占有2个字节的长度,总体占8个字节.
源端口和目的端口比较好理解,里面存储的就是发送方的端口号和接收方的端口号
UDP报文长度,描述的就是该UDP数据报(包含报头和载荷)的数据长度是多少,但是UDP报文长度这个属性只占有2个字节,也就是8个bit(0~65535),也就是说,一个UDP数据报最多可以传输64KB的数据
64KB在实际应用中是一个非常小的数据量(一个照片都能达到几MB)
那么如果一个数据的大小超过64KB,此时一个如何处理呢?
此处有两种方案:
(1)可以将数据分成多个UDP数据报,分多次传输
(2)不适用UDP,使用TCP数据报传输(TCP没有这样的限制)
第一种方式虽然可以解决上述问题,但是弊端也很明显,一个完整的数据进行拆分和组装会增加很多代码量,而且还可能出现很多bug
第二种方式还是要优于第一种方式的,就好比搬家时,是叫来多个面包车还是一个大货车的区别,多个面包车就需要去计算每个面包车上面装些什么物品,而大货车就直接一股脑的往上搬就好了,更方便快捷.
接下来就是校验和
校验和存在的意义就是:检查传输的数据是否正确
因为网络传输,说白了就是使用光信号/电信号传输
在传输的过程中,可能会由于一些物理的因素,比如:电场/磁场/高能射线等影响,使原本的数据出现了"比特翻转"的情况.
比如:原本是1111 0000 翻转后变成了 1110 0000 这两个数据的差别是很大的
而一但数据发生了改变,对其要表达的含义可能是致命的,比如:程序中经常使用1和0来表示开启和关闭,如果原本的1由于"比特翻转"变成了0,此时含义就从打开变成了关闭.
这样的情况是客观存在的,我们只能尽量去避免传递错误信息,此时就引入了校验和去校验数据是否出现改变.
如果数据发生了改变,那么校验和也会随之改变,如果发送和接收两方的计算出来的校验和不同,就会认为数据不正确
举个例子:
![](https://i-blog.csdnimg.cn/blog_migrate/9eec2b6d7e9d73463c0221eb691d7dd5.png)
发送方会先通过一些计算,根据原数据计算出一个校验和,然后接收方在根据相同的计算方式对收到的数据进行计算,如果得到的校验和不一致,说明数据出错了.
但是如果 翻转后 的数据和 翻转前 的数据计算得到的校验和相同,该怎么办呢?
上面的这种情况出现的概率极低,举个例子:
![](https://i-blog.csdnimg.cn/blog_migrate/d02f2afabbc27b4da9710efac097de5d.png)
上面这种情况理论上是客观存在的,但是由于出现的概率微乎其微,所以就直接忽略不计了,所以在实际情况中,如果校验和相同,就会认为数据是相同的.
下面我们简单说明几种比较知名的生成校验和算法:
1.CRC
它的算法简单粗暴,就是将数据(二进制)的每一位都循环往上进行累加,如果发生溢出,高位就截去.
这种算法比较好算,但是也有弊端:如果数据变动了两个bit位(前一个字节少1,后一个字节多1),此时即使数据变了,校验和也没有发生改变.
2.MD5
MD5相比于CRC,它不是简单的进行相加,而是通过一系列的公式,进行更复杂的数学运算(此处不说明).
MD5算法的特点:
(1)定长:不管你的数据是 几KB 还是几MB 甚至是几GB,得到的结果长度都是固定的(有4字节版本,8字节版本...)
(2)冲突概率小:原始数据即使改变了1位,得到的MD5值都会相差很大,会让结构更加分散
(3)不可逆:通过原始数据计算出MD5值,很容易,但是通过MD5值去计算出原始数据,很难,几乎是不可能的(计算量非常大)
同时MD5这样的特点,也会让MD5的应用场景更为广泛
比如:校验和,计算hash值,加密等