飞道的博客

Linux(服务器编程):39---项目应用层协议设计

415人阅读  评论(0)

一、协议概述

  • 什么协议:协议是一种约定,通过约定,不同的进程可以对一段数据产生相同的理解,从而可以相互协作,存在进程间通信的程序就一定需要协议
  • 为什么说进程间通信就需要协议?而不是说客户端和服务器端之前?

协议设计的目标

  • 解析效率:互联网业务具有高并发的特点,解析效率决定了使用协议的 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就不容易处理了。一般在单片机、嵌入式中使用,普遍不使用
    • 例如两端在通信的时候,数据用结构体表示,直接将结构体发送出去,不做任何序列化

   
  1. struct Data
  2. {
  3. //...
  4. };
  5. struct Data d;
  6. 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协议)

四、协议升级

  • 1. 通过版本号指明协议版本,即是通过版本号辨别不同类型的协议
  • 2. 支持协议头部可扩展,即是在设计协议头部的时候有一个字段用来指明头部的长度

五、协议安全

  • 1. xxtea 固定key
  • 2. AES 固定key
  • 3. openssl
  • 4. Signal protocol 端到端的通讯加密协议

六、数据压缩

  • 1. deflate
  • 2. gzip
  • 3. lzw

七、总结语


转载:https://blog.csdn.net/qq_41453285/article/details/106731333
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场