目录
前言
在前面,我们已经讲解过如何在java中使用UDP数据报套接字进行编程,实现了一个回显C/S程序。那么本篇我们就来讲一下有关UDP协议在应用层和传输层方面的知识。
应用层协议
应用层协议是指计算机网络中,应用程序之间通信的协议。定义了如何在不同应用程序之间进行通信和数据交换。应用层协议是计算机网络中最接近用户的一层协议,直接面向用户需求,负责处理高级数据,如文件传输、电子邮件发送等。
简单来说,应用层协议就是计算机网络通信的“语言”,使得不同计算机上的应用程序之间能够互相理解和交换信息。
应用层协议通常是由程序员自己定义的协议,用来组织数据,规定数据是如何传输和分用的。自定义一个协议需要什么呢?首先就需要明确有哪些信息要传递,再将这些信息格式化。我们现在已经有很多种方式来组织信息,但我们需要保证发送信息和接收信息的应用程序都是使用同一种信息组织方式。例如:假设现在要开发一个外卖软件,那么打开软件之后,首先需要展示的就是“商家列表”。那么此处我们需要传递的信息就有:
- 请求:需要明确用户是谁,ID,以及用户所处的位置。
- 响应:显示出商家都有哪些,每个商家又有各自的信息:名字、图片、距离、评分、价格等。
假如我们用行文本的方式来组织数据:
- 请求:用户id,用户位置\n 表示用户所处的位置:1001,E44N40\n
- 响应:商家ID,商家名称,商家图片地址,商家的距离,商家的评分;商家ID,商家名称,商家图片地址,商家的距离,商家的评分\n 表示在用户周围的各个商家的信息:2001,麻辣烫,http://image.com,1.5km,4.5;2004,霸王茶姬,http://image2.com,1km,4.8\n
但对于这个行文本的方式,我们基本上很少用这种方式来组织数据。在实际开发中,有几种比较常见的数据组织方式。
常见的数据组织方式
-
xml
-
json
-
protobuffer
1.XML
XML全称为Extensible Markup Language,即可扩展标记语言,是一种存储和传输数据的文本格式,也是一种自描述的、与平台无关的数据格式,广泛用于网络数据交换和配置文件。
特点:
- XML是一种元语言,用于创建标记语言(如HTML),与HTML不同,XML的标签需要用户自行定义,而非预定义。
- XML数据存储为纯文本格式,可以在不同系统之间传输 。
- XML具有自我描述性,能够表达数据结构,是的数据易于理解和阅读。
- XML有着严格的语法规则,包括正确的嵌套和闭合标签。
在XML文档中,数据被标记为树状结构,具有以下特点:
- XML文档必须包括根节点,这是XML文档的起点。
- XML标签必须成对出现,每一个标签开始,必须要一个对应的标签结束。
- 在XML中,大小写是有区分的。例如<Message>和<message>是两个不同的元素。
- XML文档的开始处一般有一个文档声明,定义了XML的版本、字符编码等信息。
XML应用广泛,常用于不同系统之间的数据交换;许多程序使用XML文件来存储配置信息,当然在Web服务、数据库等也有使用。
格式
<request>
<userId>1050</userId>
<position>40,50</position>
</position>
我们通过使用XML数据格式,能够提高可读性,但是在传输的时候会占用更多的带宽,所以我们可以使用另外一种可读性高且能节省带宽的数据格式----json。
2.JSON
JSON数据格式全称为:JavaScript Object Notation,是一种轻量级的数据交换格式,易于阅读和编写,同时也易于机器解析和生成,是基于JavaScript编程语言的一个子集,但独立于语言,许多编程都支持JSON。
JSON的基础结构主要包含两种类型:
- “名称/值”对的集合,通常在各种语言中被理解为对象(object)、记录(record)、结构(struct)、字典(dictionary),哈希表(hash table),或者关联数组(associative array)。每一个“名称/值”对的组合构成了一个属性(property),其中名称通常被称为属性名(property name)或者键(key),值则是属性(property value)。
- 值的有序列表,通常在大多数语言中被理解为数组(array)。数组是一种特殊的“名称/值”对集合,它的每一个元素都是一个值,而是这些值在集合中的顺序是固定的。
在JSON中,数据都是以键值对的形式从的。键是字符串,而值可以是字符串、数字等不同类型的数据。
JSON对象通常以大括号 {} 包围,并由键和值组成,例如:{key: value}。在JSON中,对象的键和值之间用冒号 “:” 分隔,而不同的键和值之间则用逗号 “,” 分隔。
格式:
json
{
"userId": 10086,
"name" : "lisi",
}
3.protobuffer
protobuffer全称为Protocol Buffers,是由Google公司开发的一种语言无关、平台无关的序列化格式,用于序列化结构化数据,数据是以二进制格式进行序列化的。类似于XML或JSON,但比它们更小、更快、更简单。
特点:
- 高效性:protobuffer序列化后的数据体积小,解析速度快;
- 语言无关:支持多种编程语言,如c++、java、Python等;
- 向后兼容性:容易对数据结构进行更新和扩展,同时保持向后兼容性;
- 定义简单:通过一个简单的.proto文件定义数据结构。
由于protobuffer数据格式是以二进制的形式组织数据的,所以在传输的过程中会采用最少的网络带宽,从而提高数据的传输速率。但同时由于protobuffer是以二进制形式组织数据的,所以代码可读性差。
接下来,我们来讲解一下有关传输层的协议,在此之前,我们来重新回顾一下端口号。
端口号
端口号是网络编程中用于标识计算机或者设备上特定服务的数字标识符。
在网络通信中,为了将数据发送到正确的接受者,我们需要对不同的应用程序进行区分,端口号就能够实现区分画呢,给每个应用程序指定一个端口号,根据端口号确保数据在复杂的网络环境中能够正确地发送和接收。
如果想要了解端口号更多的信息,可以阅读这篇文章
端口号的范围是0~65535,其中1~1023是知名端口号。例如HTTP服务使用的80端口,FTP服务使用的21端口等。
传输层
传输层在网络中主要起确定起点和终点的作用(端到端),在TCP/IP模型中位于第四层。在传输层中常见的协议是UDP协议和TCP协议。
本篇我主要讲解的是UDP协议的相关知识。
UDP协议端格式
UDP报文是由8个字节的报头和载荷组成的。载荷就是我们网络传输的数据部分,里面是完整的应用层数据报,网络传输的过程就相当于字符串拼接的过程,每达到一层,该层的协议就会给上一层传过来的数据报加上一个报头。
源端口号和目的端口号
在网络传输时,我们需要数据是由谁发起的,又要发给谁?所以在UDP报头中,16位源端口号就是指传输数据的一方哪个端口号的程序发送的数据,而16位目的端口号就是指数据由目的IP上的哪个端口接收(应用程序)。
16位比特位的范围为0~65535.
UDP长度
16位UDP长度指的是整个UDP数据报的长度,整个长度包括UDP数据报也包括UDP载荷部分(数据).
16位比特位的范围为0~65535,转换过来就是64kb(65536/1024),也就是说整个数据报能传输的最大数据位64kb,但对于我们现在来说,64kb是一个很小的数据了。我们现在拍一张照片都要几mb了。
如果我们使用UDP协议来传输一个非常大的数据会怎么样?
在使用UDP协议来传输数据的时候,UDP报头会记录UDP的长度,当接收方拿到数据报就会对数据报进行分用拆包,在分用的时候就会根据UDP报头中存储的长度来读取数据,由于UDP最多能存储的数据只有64kb,所以超出部分就不会被读取,导致部分数据丢失。
既然16位的UDP长度不能满足一些比较大的数据传输,那么我们可以将UDP长度改为4个字节、8个字节吗?
其实是可以的,但这是不允许的,你如果修改了,那么其他人在接受数据的时候就会读取错误,所以要么就全部改,不然就不改。相比于修改UDP的长度,未来发明出新的协议比这都可能要简单。那么是否可以将数据分解为一个一个小数据传输呢?其实也是可以的,但这样实现分包和拆包的过程充满不确定性,所以不能使用。
由于UDP长度受限,所有在传输大数据的时候,我们往往会选择使用TCP进行传输。
校验和
我们在网络传输的过程中,其实是非常容易出现错误的,在物理层传输中,电信号/光信号/电磁波在传输的时候,容易受到环境的干扰,导致里面传输的信号发生改变,所以我们就需要用到校验和,校验和就是为了能够发现或者纠正这些错误。
UDP校验和是UDP数据报中添加的一项用于检测数据传输是否有误的校验机制,是一种简单的错误检测方法,通过给每个数据报添加一份校验和,接收方可以验证数据是否有误。
在UDP协议中,校验和是由发送端计算出来的,在发送数据报给接收端时,接收端会计算一下校验和,并和接收到的校验和进行比较,如果校验和相同,接收端就认为数据无误。
那么如何基于校验和来校验数据呢?
- 1.发送端将要发送的数据打包成data1,同时计算出校验和checksum1;
- 发送端将data1和校验和checksum1发送出去。
- 接受端通过网络接收到data2和校验和checksum1.
- 接收端同样计算出校验和checksum2
- 判断checksum1和checksum2是否相同
如果相同,说明数据data1和data2基本相同。
如果不相同,说明数据data1和data2一定不一样。
这里UDP中的校验和使用的是CRC算法(循环冗余算法):把当前要计算校验和的数据的每个字节都累加起来,将这个计算出来的和保存到两个字节的校验和中,既然在计算校验和时出现了溢出问题,也不会有问题,并不会影响最终结果。
但这个CRC是一个不靠谱的算法。当数据在传输的时候,如果我在前面有个字节少了一部分数据,而后面再某个字节中又恰好多了一部分数据,且少了的数据恰好和多了的数据一致。那么此时计算出来的校验和就是相等的,此时就会认为数据在传输的时候没有出现问题,但实际数据是有问题的。
除了上述我们说的CRC计算校验和外,我们还有一些其他计算校验和的方法,如MD5,SHA1,这两个方法在计算校验的正确率要比CRC更高,这里我们就来介绍一下MD5。
MD5算法本质上是一个“字符串hash算法”(适合做检验和、哈希、加密算法)
特点:
- 定长:无论输入的字符串有多长,算出的MD5都是固定长度的。
- 分散:输入的内容,哪怕只有一点点发生改变,得到的MD5值都会相差很大。
- 不可逆:根据输入的内容,计算出MD5非常简单,但是要还原出原始的内容,理论上是行不通的。现如今的算力也是非常难解出来的。
SHA1跟MD5类似,同样有以上3个特点。
我们可以看到,无论输入的数据多长,最后计算出来的长度都是固定的。
同时,我们也可以看到,就算相差一个字符,两个MD5值相差也是非常大的。
以上就是本篇UDP协议所有内容咯~
若有不足之处,欢迎指正~