简谈网络协议那些事

前言

通信协议是两个节点为协同工作、交换信息而约定的规则,包括字节序、字段类型、压缩或加密方法等。常见的前端协议如 TCP、UDP、HTTP、SIP 等,都包含流程规范(如信令流程)和编码规范(即数据打包/解包规则)。 编码规范也称作序列化或编解码,不仅用于通信,也常用于存储场景,比如将内存中的对象保存到磁盘。

本文通过一个个简单逐步演进的示例,展示一个协议从简单到完善的设计过程,帮助你理解编码协议。


1. 紧凑模式

一开始,我们定义一个简单的用户基本信息结构:

c 复制代码
struct userbase {
    unsigned short cmd;  // 1-get, 2-set
    unsigned char gender; // 1-man, 2-woman
    char name[8];        // 定长姓名
}

这种方式几乎无需编码是一种row数据,数据直接从内存拷贝、调整字节序后发送。接收方也能正确解析。

其编码格式如下(每格一字节):

scss 复制代码
| cmd (2) | gender (1) | name (8) |

这就是"紧凑模式":除了原始数据,没有额外信息。在早期资源紧张的时代很常见,你想扩展或者做点其他事情几乎不可能,你被限制在仅有的空间内,位置不能移,大小不能动。


2. 可扩展性

当我们需要增加一个新字段时,问题出现了:接收方无法正常读取,协议无法正常通信。

于是早期引入版本号概念:

c 复制代码
struct userbase {
    unsigned short version;
    unsigned short cmd;
    unsigned char gender;
    unsigned int birthday;
    char name[8];
}

这样通过版本号区分新旧结构,实现了基本扩展能力。

但是弊端也是看得见的,协议版本无数多,你要维护大量的版本分支,随着版本迭代的的这种难度大到已经足以让大家放弃。重新寻找更合适的方案也就迫在眉睫。


3. 更灵活的扩展性

但仅靠版本号管理,随着版本增多,就如上面说的代码中会出现大量分支判断,难以维护。 我们为每个字段增加一个标签(tag),形成类似键值对的结构:

复制代码
| version | cmd | gender | birthday | name |

虽然增加了冗余,但换来了更好的灵活性和可读性。


4. 变长字段支持

现实中很多字段是变长的,比如姓名可能超过8字节。固定长度既浪费也不灵活。

这里可以借鉴 ASN.1 的 BER 编码方式,使用 TLV 格式:

css 复制代码
[Tag][Length][Value]

例如用户信息可编码为:

复制代码
| tag_cmd | len_cmd | cmd | tag_gender | len_gender | gender | tag_name | len_name | name... |

TLV具备了很好可扩展性,很简单易学。同时也具备了缺点,因为其增加了2个额外的冗余信息,tag 和len,特别是如果协议大部分是基本数据类型int ,short, byte. 会浪费几倍存储空间。另外Value具体是什么含义,需要通信双方事先得到描述文档,即TLV不具备结构化和自解释特性。


5. 加入自解释性

为了不依赖外部文档就能理解数据含义,我们在 TLV 基础上增加类型信息,形成 TTV

css 复制代码
[Tag][Type][Value]

其中定义了基本类型(如 int、short)可省略 Len,因为长度是已知固定的。

我们定义一套类型值:

go 复制代码
1: int16, 2: int32, 3: string, ...

编码后数据类似:

复制代码
| tag_cmd | type_cmd | cmd | tag_name | type_name | len_name | name... |

这样即使没有协议文档,也能解析出字段类型和含义。


6. 跨语言支持

当多语言协作时(如 Java/PHP 不支持无符号类型),需统一类型系统,避免兼容问题。

我们定义一套跨语言通用类型(即:交集类型),约束使用范围,保证各语言解析一致性。


7. 代码自动化

手动编解码枯燥易错,我们引入 IDL 来描述协议,通过工具自动生成不同语言的代码:

复制代码
gen_cpp sample.idl  → sample.cpp, sample.h
gen_java sample.idl → sample.java

提升效率,减少错误。


总结

从上文的介绍大致可以了解到协议设计是一个逐步完善的过程:

  • 紧凑模式 出发,逐步考虑扩展性
  • 引入标签类型实现自解释
  • 通过统一类型系统支持跨语言
  • 借助 IDL 和代码生成提升开发效率
  • 最终形成支持压缩、可选字段等特性的成熟协议

最后这篇文章大部分的知识来源互联网,在自己理解的基础上进行编写没有很生涩难懂的技术细节,本人知识的广度不足以支撑更多,如大佬略过即可。

相关推荐
小李独爱秋3 小时前
计算机网络经典问题透视:TLS协议工作过程全景解析
运维·服务器·开发语言·网络协议·计算机网络·php
不穿格子的程序员4 小时前
计算机网络篇1:OSI + HTTP进化史 + 三次握手四次挥手
网络协议·计算机网络·http
常温5104 小时前
关于网卡如何给CPU减负方法及策略
网络协议·tcp/ip·udp
莫小墨4 小时前
Modbus协议
网络协议
汤愈韬5 小时前
防火墙双机热备技术之VRRP
网络·网络协议·网络安全·security·huawei
北京耐用通信5 小时前
告别通信干扰与距离限制:耐达讯自动化Profibus总线光纤中继器赋能伺服驱动器稳定连接
人工智能·科技·网络协议·自动化·信息与通信
乾元6 小时前
10 个可复制的企业级项目:从需求到交付的 AI 网络工程模板(深度实战版)
运维·网络·人工智能·网络协议·安全
我是海飞6 小时前
杰理 AC792N WebSocket 客户端例程使用测试教程
c语言·python·单片机·websocket·网络协议·嵌入式·杰理
刘某某.6 小时前
RPC分类
网络·网络协议·rpc
石像鬼₧魂石7 小时前
windows系统139/tcp与445/tcp端口渗透完整流程闭环(复习总结)
windows·网络协议·tcp/ip