简谈网络协议那些事

前言

通信协议是两个节点为协同工作、交换信息而约定的规则,包括字节序、字段类型、压缩或加密方法等。常见的前端协议如 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 和代码生成提升开发效率
  • 最终形成支持压缩、可选字段等特性的成熟协议

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

相关推荐
AI人工智能+电脑小能手6 小时前
【大白话说Java面试题 第210题】【10_网络协议篇】第1题:说说 TCP/IP 网络五层模型
java·网络协议·tcp/ip·计算机网络·网络五层模型
不在逃避q6 小时前
使用.NET实现自带思考的Tool 并且提供mcp streamable http服务
网络协议·http·.net
K成长日志7 小时前
BLE链路层空口包--数据物理信道PDU
网络·物联网·网络协议·嵌入式·蓝牙·iot·ble
treesforest16 小时前
IP定位技术在网络犯罪侦查中的应用与价值
网络·网络协议·tcp/ip·网络安全·ip归属地查询·反欺诈
外滩运维专家16 小时前
HTTPS 证书报错排查手册:6 个高频错误码及解决方法
网络协议·http·https
起司喵喵18 小时前
通过Certbot自动申请更新HTTPS网站的SSL证书
网络协议·https·ssl
鲜花飘飘扬20 小时前
HTTP请求头中表示代理IP地址的属性及获取情况
网络协议·tcp/ip·http
paopaokaka_luck1 天前
基于springboot3+vue3的智能文库平台(AI智能搜索、AI智能汇总、实时在线状态展示、多格式文档预览与富文本编辑、Echarts图形化分析)
前端·网络·spring boot·网络协议·echarts
发光小北1 天前
SG-RS232/485/422-Fiber-110 串口光纤收发器如何使用?
网络协议
M158227690551 天前
工业跨网段通信零改造方案!SG-NAT-210/410 NAT 网关全功能解析,不改 PLC IP 实现多协议互通
网络·网络协议·tcp/ip