一、协议概述
- 什么协议:协议是一种约定,通过约定,不同的进程可以对一段数据产生相同的理解,从而可以相互协作,存在进程间通信的程序就一定需要协议
- 为什么说进程间通信就需要协议?而不是说客户端和服务器端之前?
协议设计的目标
- 解析效率:互联网业务具有高并发的特点,解析效率决定了使用协议的 CPU成本;编码长度:信息编码出来的长度,编码长度决定了使用协议 的网络带宽及存储成本
- 易于实现:互联网业务需要一个轻量级的协议,而不是大而全的
- 可读性:编码后的数据的可读性决定了使用协议的调试及维护成本(不 同的序列化协议是有不同的应用的场景)
- 兼容性:互联网的需求具有灵活多变的特点,协议会经常升级,使用协 议的双方是否可以独立升级协议、增减协议中的字段是非常重要的
- 跨平台跨语言:互联网的的业务涉及到不同的平台和语言,比如 Windows用C++,Android用Java,Web用Js,IOS用object-c
- 安全可靠:防止数据被破解
协议设计最核心的问题(文章下面会详细介绍)
- 1. 序列化/反序列化
- 2. 判断包的完整性
- 3. 协议升级
- 4. 协议安全
- 5. 数据压缩
二、序列化与反序列
- 序列化和反序列化概念:
- 序列化:把对象转换为字节序列的过程称为对象的序列化
- 反序列化:把字节序列恢复为对象的过程称为对象的反序列化
- 数据格式存储一般有两种:
- 一种为文本存储(例如JSON、XML等),另一种为二进制存储(例如Protobuf)
- 二进制可读性差,文本存储可读性高
- 用二进制存储比用本文存储占用的空间更少(如下图所示,12345678用文本存储需要8字节,用十六进制存储只需要6字节)。
序列化方法
- ①TLV编码及其变体(TLV是tag, length和value的缩写):比如Protobuf(Protobuf详情参阅:https://blog.csdn.net/qq_41453285/article/details/106731318)
- ②文本流编码:比如XML/JSON
- ③固定结构编码: 基本原理是,协议约定了传输字段类型和字段含义,和TLV的方式类似, 但是没有了tag和len,只有value。比如TCP头部,其头部已经是固定的了
- ④内存dump:
- 基本原理是,把内存中的数据直接输出,不做任何序列化操作。反序列化的时候,直接还原内存
- 如果消息结构是嵌套类型的,例如JSON那样的,那么内存dump就不容易处理了。一般在单片机、嵌入式中使用,普遍不使用
- 例如两端在通信的时候,数据用结构体表示,直接将结构体发送出去,不做任何序列化
struct Data { //... }; struct Data d; send(fd, &d, sizeof(d), 0);
主流序列化协议
- 主流序列化协议:
- XML 指可扩展标记语言(eXtensible Markup Language)。是一 种通用和重量级的数据交换格式。以文本方式存储
- JSON(JavaScript Object Notation,JS对象简谱)是一种通用和轻量 级的数据交换格式。以文本结构进行存储
- protocol buffer是Google的一种独立和轻量级的数据交换格式。以二进制结构进行存储
序列化、反序列化速度对比
- 测试10万次序列化
- 测试10万次反序列化
三、判断包的完整性
- 为了能让对端知道如何给包分界,目前一般有以下做法:
- 1. 以固定大小字节数目来分界,如每个包100个字节,对端每收齐100个字节,就当成 一个包来解析
- 2. 以特定符号来分界,如每个包都以特定的字符来结尾(如\r\n),当在字节流中读取到该字符时,则表明上一个包到此为止
- 3. 固定包头+包体结构,这种结构中一般包头部分是一个固定字节长度的结构,并且 包头中会有一个特定的字段指定包体的大小。收包时,先接收固定字节数的头部, 解出这个包完整长度,按此长度接收包体。这是目前各种网络应用用的最多的一种 包格式
- 4. 在序列化后的buffer前面增加一个字符流的头部,其中有个字段存储包总长度,根据特殊字符(比如根据\n 或者\0)判断头部的完整性。这样通常比3要麻烦一些, HTTP和REDIS采用的是这种方式。收包的时候,先判断已收到的数据中是否包含结 束符,收到结束符后解析包头,解出这个包完整长度,按此长度接收包体
协议设计范例参考1(云平台节点服务器)
协议设计范例参考2(即使通信项目)
协议设计范例参考4(Nginx)
- 下面是Nginx数据包头部的定义
协议设计范例参考4(HTTP协议)
- HTTP协议是我们最常见的协议,我们是否可以采用HTTP协议作为互联网后台的协议呢?这个一般是不适当的,主要是考虑到以下2个原因:
- 1)HTTP协议只是一个框架,没有指定包体的序列化方式,所以还需要配合其他序列化的方式使用才能传递业务逻辑数据
- 2)HTTP协议解析效率低,而且比较复杂(不知道有没有人觉得HTTP协议简单,其实不是http协议简单,而 是HTTP大家比较熟悉而已)
- 有些情况下是可以使用HTTP协议的:
- 1)对公网用户api, HTTP协议的穿透性最好,所以最适合
- 2)效率要求没那么高的场景
- 3)希望提供更多人熟悉的接口,比如新浪微、腾讯博提供的开放接口
协议设计范例参考5(Redis的Resp协议)
- 基本原理是:先发送一个字符串表示参数个数,然后再逐个发送参数,每个参数发送的时候,先发送一个字符串表示参数的数据长度,再发送参数的内容
- 详情参阅:https://blog.csdn.net/qq_41453285/article/details/106084527
四、协议升级
- 1. 通过版本号指明协议版本,即是通过版本号辨别不同类型的协议
- 2. 支持协议头部可扩展,即是在设计协议头部的时候有一个字段用来指明头部的长度
五、协议安全
- 1. xxtea 固定key
- 2. AES 固定key
- 3. openssl
- 4. Signal protocol 端到端的通讯加密协议
六、数据压缩
- 1. deflate
- 2. gzip
- 3. lzw
七、总结语
- JSON语法可以参阅:https://blog.csdn.net/qq_41453285/article/details/106699314
- XML语法可以参阅:https://blog.csdn.net/qq_41453285/article/details/106725959
- Protobuf语法可以参阅:https://blog.csdn.net/qq_41453285/article/details/106731318
转载:https://blog.csdn.net/qq_41453285/article/details/106731333
查看评论