目录
TCP/IP五层协议
应用层 -- 传输层 -- 网络层 -- 数据链路层 -- 物理层。
应用层
应用层和应用程序直接相关,是和程序员打交道最多的一层。
应用层协议里面描述的内容就是你写的程序,通过网络具体按照啥样的方式来传输数据,不同的应用程序就可以用不同的应用层协议。在实际开发中,很多时候需要自己去自定制应用层协议的。
自定义应用层协议,本质上就是对传输的数据做出约定:
1.约定传输的数据要有那些信息。
2.传输的数据要遵守什么样的格式。
如何自定义应用层协议?
1.确定传输信息
客户端发送请求,服务器响应数据。
比如开发一个外卖软件,用户发送请求:用户的id和所在位置,服务器返回响应:商家列表,商家名称,商家图片,商家评分简介等。
2.确定数据格式
上述的数据都属于"结构化数据"(通过结构体来表示的数据),网络上传输的是字符串(二进制字符串),就需要对数据进行序列化。
序列化方式
1.基于行文本的方式来传输
例如:
请求:用户id,位置信息
1234 180E40N
响应:商家名称,商家图片,商家评分
凉皮 图片地址 9.2
这种格式属于自定义格式,包含的信息,分割符都可以灵活控制,只需要确保客户端和服务器使用同一套规则进行通信即可。但是这套规则的可维护性比较差,当属性多了的时候,看上去混乱。
2.基于xml的方式
一种经典的数据组织格式:
请求:
<request>
<userId>1234</userId>
<position>180E40N</position>
</request>
在使用maven使就是通过xml来配置管理的。
3.基于json的方式
使用{ }作为边界,里面是键值对,键值对之间,使用 ,进行分割,键和值之间使用 :进行分割:
请求:
{
userId: 1234,
position: "180E40N"
}
可读性好,而且比xml更简洁。
4.yml的形式
属于缩进格式,通过缩进来表示包含/嵌套关系。xml通过标签来表示嵌套关系,yml通过缩进来表示的。并且对于缩进是强制要求的,可读性也很好,缩进不正确就会出错。
5.protobuffer(pb)形式
前面几种形式都是文本格式,肉眼可以看懂,pd则是二进制数据,肉眼看不懂。对于传输效率要求高的场景推荐使用这种方式,针对数据进行进一步的整理和压缩,虽然可读性不好,但是能够把空间最充分的利用,最节省网络宽带,效率也最高。
传输层
socket api都是由传输层协议提供的,操作系统内核实现。
端口号
端口号就是传输层提供的概念,用来寻找主机上的应用程序。端口号是一个整数,使用两个字节表示的无符号整数:0 -> 65535,其中,小于1024的端口号称为知名端口号,把这些端口号分配给一些比较知名的服务器程序作为这些服务器的"默认端口号",自己写的服务器程序要避免知名端口号。
同一个机器上,同一时刻,端口号不能重复被绑定。可以使用 netstat 命令查看当前主机上是否有使用9090端口的进程,打开终端,输入命令:
9090端口号没有被使用,8080端口号被使用。两个进程不能同时绑定一个端口号。
协议
UDP: 无连接,不可靠传输,面向数据报,全双工
TCP:有连接,可靠传输,面向字节流,全双工
UDP
应用层数据到达UDP之后,就会给应用层数据报前面拼装上UDP报头。
UDP数据报 = UDP报头(8字节) + UDP载荷
一个UDP数据报,,最长就是64kb,UDP长度就描述了整个UDP数据报占多少个字节,通过UDP长度就能知道当前载荷一共是多少字节。如果使用UDP开发程序,就会有很大的限制,要确单个数据报在传输时不能超过64KB。
校验和
数据在网络传输中是可能会"出错"的。如比特翻转:
传输数据时是传输的二进制数,假设传输的是 0,但是实际到达对端却变成了1。
这是因为数据在传输过程中变为电信号/光信号/电磁波的形式,可能受到外界干扰。比如电信号,在电信号中使用 0表示高电平,使用 1 表示低电平,此时如果在传输过程中,遇到一个变化的磁场,就会把原来 的高电平/低电平变为低电平/高电平,这就需要能够对传输的数据进行校验。UDP就使用CRC的方式来对错误信息进行校验。
校验和是数据引入冗余信息,通过冗余信息来验证原有的数据。就是拿着数据一部分进行一系列计算,得到的结果,如果数据发生变化,此时得到的结果也不一样。
CRC
UDP中使用CRC算法作为校验和,CRC是一个简单粗暴的计算校验和的方式,循环冗余校验 。
设定两个字节的变量,把数据每个字节都取出来,往这个变量上进行累加,如果结果溢出,超过两个字节的溢出部分就舍弃。
TCP
TCP协议机制较复杂,下篇文章进行详解。
感谢观看