2. 协议基础回顾:OSI七层模型、TCP/IP协议栈、常见协议格式

做协议适配,说白了就是跟不同年代的“通信规矩”打交道。你想想看,一个设备说Modbus,另一个设备说MQTT,中间怎么传话?

我个人习惯,遇到这种问题先退一步——把协议分层模型捋清楚。模型不乱,适配方案就不会跑偏。

2.1 OSI七层模型——通信的“理想国”

OSI七层模型是国际标准化组织(ISO)在1984年提出的。它把通信过程拆成7层,每层只管自己的事。

我记得刚入行时,师傅让我背这七层,我死活记不住。后来他教我一个口诀:“物链网传会表应”。嗯,到现在都没忘。

层号 名称 核心职责 典型协议/设备
7 应用层 为用户提供网络服务接口 HTTP、MQTT、FTP、Modbus(应用层)
6 表示层 数据格式转换、加密、压缩 SSL/TLS、JPEG、ASCII
5 会话层 建立、管理、终止会话 NetBIOS、RPC
4 传输层 端到端可靠传输 TCP、UDP
3 网络层 路由选择、逻辑寻址 IP、ICMP、ARP
2 数据链路层 帧封装、差错检测、MAC寻址 Ethernet、PPP、MAC地址
1 物理层 比特流传输、电气特性 RS-485、RJ45、光纤
我的经验: 做协议适配时,我只看三层——应用层、传输层、物理层。中间那几层,大部分场景下被操作系统和库给包办了。但如果你遇到串口转以太网、或者非IP网络(比如LoRa),那物理层和数据链路层就得仔细看。

2.2 TCP/IP协议栈——工业界的“真香”模型

OSI模型太完美,完美到没人用。实际工业界和互联网用的是TCP/IP协议栈,也叫“事实标准”。

它只有四层:应用层、传输层、网络层、网络接口层。说白了就是把OSI的上三层合并成应用层,下两层合并成网络接口层。

核心对比:
  • OSI:理论完整,适合教学和协议设计参考
  • TCP/IP:实用至上,适合开发和部署

我在项目中遇到过客户非要按OSI七层来写适配文档,结果开发时发现底层库根本不暴露会话层接口。最后我们按TCP/IP四层重新梳理,效率高了很多。

2.3 常见协议格式——手撕报文的能力

做协议适配,最核心的能力是什么?我个人觉得是“手撕报文”。

你不需要背下每个字节,但要知道去哪里找、怎么看。下面我挑三个最常见的协议,说说它们的报文结构。

2.3.1 HTTP——Web世界的通用语

HTTP是文本协议,说白了就是一堆ASCII字符串。请求和响应都分三部分:起始行、头部、正文。

// HTTP请求示例
POST /api/data HTTP/1.1
Host: 192.168.1.100:8080
Content-Type: application/json
Content-Length: 27

{"temperature": 25.5}

// HTTP响应示例
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 18

{"status": "ok"}
避坑指南: 我曾经调试一个设备,HTTP请求总是超时。抓包一看,Content-Length算错了,多了一个空格。HTTP头部每个字段后面必须是\r\n,正文和头部之间必须有一个空行(\r\n\r\n)。少一个回车,服务器就不认。

2.3.2 MQTT——物联网的轻量级选手

MQTT是二进制协议,基于发布/订阅模式。它的报文头固定只有2个字节,非常省带宽。

// MQTT固定头格式(2字节)
Byte 0: 消息类型(4bit) + 标志位(4bit)
Byte 1: 剩余长度(可变长编码)

// 常见消息类型
0x30 = PUBLISH(发布消息)
0x82 = SUBSCRIBE(订阅主题)
0x90 = SUBACK(订阅确认)
0xE0 = PINGREQ(心跳请求)

MQTT的“剩余长度”字段用了可变长编码,每个字节最高位是延续位。我刚开始看的时候觉得多此一举,后来在窄带物联网项目里才发现,这种设计能省下大量字节。

我的习惯: 调试MQTT时,我会先用Wireshark抓包,过滤mqtt,然后看报文类型和Topic。如果设备频繁断连,先检查心跳间隔(Keep Alive)和遗嘱消息(Will Message)的设置。

2.3.3 Modbus——工业现场的“老黄牛”

Modbus是1979年诞生的协议,到现在还在大量使用。它分两种:Modbus RTU(串口,二进制)和Modbus TCP(以太网)。

// Modbus RTU 报文格式(主机请求)
地址码(1B) | 功能码(1B) | 数据(nB) | CRC校验(2B)

// 示例:读取从站地址0x01的保持寄存器,起始地址0x0000,读取2个寄存器
01 03 00 00 00 02 C4 0B

// 功能码速查
0x01 = 读线圈
0x02 = 读离散输入
0x03 = 读保持寄存器
0x06 = 写单个寄存器
0x10 = 写多个寄存器
我曾经踩过的坑: Modbus RTU的CRC校验是低字节在前。有一次我写适配代码,CRC算对了但顺序搞反了,从站一直不回包。排查了整整半天才发现是字节序问题。记住:Modbus RTU是小端模式,Modbus TCP没有CRC,靠TCP本身的校验。

2.4 协议分层与适配的关系——一张图说清楚

下面这张图,是我自己总结的“协议适配分层映射图”。它帮你快速定位:当两个协议不通时,问题出在哪一层。

协议适配分层映射图 设备A(Modbus RTU) 应用层:Modbus 传输层:无(串口直连) 物理层:RS-485 协议适配器 Modbus → MQTT 协议转换 地址映射 数据格式重组 缓存与重传 设备B(MQTT over TCP) 应用层:MQTT 传输层:TCP 物理层:以太网 串口数据 TCP数据 MQTT应答 Modbus应答 适配要点: 1. 物理层不同:RS-485 ↔ 以太网,需要硬件转换 2. 传输层不同:无传输层 ↔ TCP,需要建立连接管理 3. 应用层不同:Modbus请求/响应 ↔ MQTT发布/订阅,需要语义映射 4. 数据格式不同:二进制 ↔ JSON,需要序列化/反序列化
核心结论: 协议适配的本质,是在不同层次上做“翻译”。物理层不同就加转换器,传输层不同就做连接映射,应用层不同就做语义转换。不要试图在应用层解决物理层的问题,也不要忽略传输层的差异直接做数据转发。

2.5 本章小结

协议基础回顾到这里。记住三件事:

  • OSI七层是理论框架,帮你理解“通信到底分几步”
  • TCP/IP四层是实战模型,开发时按这个来
  • HTTP、MQTT、Modbus是三个最常见的协议,它们的报文结构必须烂熟于心