互联网中,主流的是 TCP/IP 五层协议
- 5G/4G 上网,是有自己的协议栈,要比 TCP/IP 更复杂(能够把 TCP/IP 的一部分内容给包含进去了)
应用层
可以代表我们所编写的应用程序,只要应用程序里面用到了网络通信,就可以认为这个代码就是属于应用层的代码
日常开发中最常用到的一层:
- 使用大佬们已经创建好的应用层协议
- 应用层知名的协议有很多,其中的佼佼者就是
HTTP
- 应用层知名的协议有很多,其中的佼佼者就是
- 自己定义应用层协议
- 另外四层都是操作系统/硬件/驱动已经实现好了的,我们不可能“自定义”,只能使用人家的
协议就是约定
- 按照自己的规则,约定通讯方式——>自定义应用层协议
自定义应用层协议
自定义应用层协议,具体要做什么事情:
明确要传递的信息
- 明确前后端交货过程中,要传递哪些信息
举个例子:开发一个外卖软件,打开软件后,首先需要展示一个“商家列表”
此处就需要先确定传递的信息是什么
- 请求:用户是谁(用户的 ID),用户所处的位置
- 响应:商家列表,包含多个商家,每个商家信息中,又有商家的名字、图片、距离、评分
这里的信息如何确定,都是根据当前的需求来产生的
明确组织信息的格式
- 明确组织这些信息的格式
针对信息组织格式,也有很多种方式,使用哪种方方式都可以,只要确定前段和后端是同一种方式就可以了
举个例子:使用行文本的方式来组织上述数据
- 请求:
用户id,用户位置\n
- 响应:
商家的id,商家名称,商家的图片地址,商家的距离,商家的评分\n
关于组织数据的格式,还有一些说法,上述“行文本”简单粗暴的方案,在实际开发中,很少会这样做
XML 方案
Maven 中就会见到,通过“成对的标签”表示“键值对”信息
<request>
<userid>1001</userid>
<postion>E45N60</postion>
</request>
- 可以通过
XML
来传输网络数据,也可以作为程序的配置文件 - 不过
XML
进行网络传输的时候,又有一个明显的缺点——会消耗大量的带宽- 网络通信中,带宽是一个非常贵的硬件设备
- 在传输标签的时候,都得传输成对的标签,传入的信息更多
- 所以现在
XMl
一般都是在配置文件,不进行网络传输了 XMl
里面的标签(键值对)都是程序员固定的,而HTMl
里面的标签都是固定的(已经有一套标准,约定好哪些标签是合法标签,这些标签都是什么含义)
JSON 方案
当前主流的网络通信的数据格式,相比 xml
来说,可读性是很好的,同时能节省一定的带宽
{
"userid":1001,
"postion":""E45N60"
}
JSON
也是“键值对”格式,- 键和值之间用
:
分割 - 键值对之间用
,
分割 - 所有的键值对,都使用
{}
括起来
- 键和值之间用
- 这里的标签都只有一份,不需要结束标签了,节省了传递开销
YML(YAML)方案
强制要求了数据组织的格式,强制要求写成“可读性非常高”的格式
- 键值对必须独占一行
- “嵌套”结构必须通过缩进来表示
protobuffer方案
前三个方案,都是关注可读性,而 protobuffer 关注性能,牺牲了可读性(通过二进制的方式组织数据)
- protobuffer 直接通过“位置”约定字段的含义,不需要传输 key 的名字,也会针对传输的数值,进行二进制的编码,起到一些“压缩”的效果
- 极大地缩减了要传输的数据的体积——>带宽消耗就越小——>效率越高
- 但二进制数据无法肉眼阅读,调试相关程序的时候,就会比较麻烦
常见端口号
端口号是一个整数,用来区分不同的进程。
- 同一时刻,同一个机器上,同一个协议,一个端口号只能被一个进绑定
- 一个进程可以绑定多个端口号
- 端口号是通过两个字节的无符号整数表示的,取值范围 0~65535,但实际上 0 比较特殊,一般不会使用
- 1~1023 属于已经被预定好的(有一些知名的服务器,已经提前预定了这个端口),这样的端口称为“知名端口号”(其实里面的大部分服务器已经不再使用了,在 80、90 年代是知名的)
- 我们日常开发的时候,会避开这些端口
业务端口和管理端口
什么时候会涉及到一个进程(服务器)绑定多个端口?
- 编写服务器,肯定需要先绑定至少一个端口号,和客户端进行交互(称为“业务端口”)
- 服务器运行过程中,希望能够对这个服务器的行为,进行一些“控制”
- 比如让服务器重新加载某个数据/某个配置/修改服务器的某个功能
- 也可以通过网络通信完成上述功能
- 就可以让服务器绑定另一个端口,通过这个端口,编写一个客户端,给服务器发送一些“控制类“请求
- 上面的“另一个端口”就是“管理端口“
调试端口
当需要针对服务器运行状态进行检测和调试,需要查看服务器运行中某个关键变量的数值的时候,千万不能用调试器来进行调试,一旦使用调试器调试这个服务,就会使服务器的一些线程被阻塞住,无法给客户端正确提供服务了
- 虽然可以通过日志进行打印,但是不方便,需要修改代码并重启服务器
- 可以让服务器绑定另一个端口,然后实现一些相关的打印关键变量的逻辑,客户端发送对应的调试请求
- 这里的“另一个端口”就是“调试端口”