4、协议基础:基于TCP/IP的通信协议栈与报文结构

各位好,我是老轨。今天咱们聊聊PIS系统和列车控制系统之间通信的“底层语言”——TCP/IP协议栈和报文结构。这部分内容,说白了就是两个系统之间怎么“说话”、怎么“听懂对方”。

我在现场调试的时候,遇到过不少因为协议理解不透彻导致的通信故障。你想想看,两个系统明明都通电了,网线也插好了,可就是“鸡同鸭讲”。嗯,问题多半出在协议栈的某一层上。

4.1 为什么选择TCP/IP?

我个人习惯,在轨道交通信号系统里,首选就是TCP/IP。为什么?

  • 可靠性高:TCP的确认重传机制,能保证报文不丢、不乱序。这在信号系统里是底线。
  • 跨平台性好:无论是Windows、Linux还是嵌入式系统,TCP/IP都是标配。
  • 分层清晰:每一层各司其职,出了问题好排查。

核心要点:PIS与TCMS(列车控制管理系统)之间的通信,我建议统一采用TCP协议,端口号建议固定为5000-5005区间,避免冲突。

4.2 协议栈的四层模型

咱们不搞那些花里胡哨的七层模型,轨道交通现场,四层模型就够用了。我给大家拆开讲讲:

层级 名称 作用 现场常见问题
第4层 应用层 定义报文格式、业务逻辑 报文解析错误、字段对齐问题
第3层 传输层 TCP/UDP端口管理、可靠传输 端口被占用、连接超时
第2层 网络层 IP地址路由、寻址 IP冲突、子网掩码不匹配
第1层 链路层 MAC地址、物理介质访问 网线接触不良、交换机端口故障

我的经验:排查通信故障时,从第1层往上查。先看网口灯亮不亮,再ping IP,最后抓包看应用层。这个顺序能省你半天时间。

4.3 报文结构设计

好了,协议栈选好了,接下来就是报文长什么样。我在项目中用过不少报文格式,最后沉淀下来一套比较通用的结构,分享给大家:

| 帧头(2字节) | 长度(2字节) | 类型(1字节) | 序列号(2字节) | 时间戳(4字节) | 数据域(N字节) | 校验(2字节) | 帧尾(2字节) |
|    0xAA55   |   N+13      |   0x01      |   0x0001     |   Unix时间戳  |  实际数据     |  CRC16      |   0x55AA   |

每个字段的含义,我挨个说一下:

  • 帧头(0xAA55):固定值,用于同步。我曾经遇到过一帧数据中间断了,靠这个帧头重新找到起始位置。
  • 长度字段:从类型字段开始到校验字段结束的总字节数。注意,这个长度不包含帧头和帧尾。
  • 类型字段:区分不同业务。比如0x01是状态上报,0x02是控制指令。
  • 序列号:每发一帧加1,用于去重和排序。嗯,这个在丢包重传时特别有用。
  • 时间戳:Unix时间戳,精确到秒。PIS系统需要根据这个时间戳做信息同步。
  • 数据域:真正的业务数据,长度可变。
  • 校验(CRC16):对整个报文(从帧头到数据域)做循环冗余校验。我曾经因为校验算法写错,排查了整整两天……
  • 帧尾(0x55AA):固定值,表示报文结束。

避坑指南:我曾经见过一个项目,帧头和帧尾用了相同的值(比如都是0xAA55)。结果接收方在解析时,把帧尾误判成了帧头,整个报文解析全乱套了。记住:帧头和帧尾一定要不同!

4.4 实际通信流程

光有报文结构还不够,还得知道怎么“握手”。我给大家画个简单的流程:

  1. 建立连接:PIS系统作为客户端,主动向TCMS的5000端口发起TCP连接。
  2. 发送心跳:连接建立后,每1秒发送一次心跳报文(类型0x00),保持连接活跃。
  3. 数据交互:TCMS收到心跳后,回复状态报文(类型0x01)。PIS根据状态报文,决定是否下发控制指令。
  4. 断开连接:列车断电或系统关闭时,主动发送FIN包断开连接。

关键点:心跳超时时间我建议设为3秒。超过3秒没收到心跳,就认为连接断了,需要重新建立。这个值是我在多个项目里试出来的,太短容易误判,太长反应太慢。

4.5 数据域的具体定义

数据域里装什么?以PIS系统最常用的“列车到站信息”为例:

| 车站ID(2字节) | 到站时间(4字节) | 开门方向(1字节) | 预留(1字节) |
|    0x0012     |   0x5F4E3D2C   |     0x01        |   0x00      |
  • 车站ID:0x0012表示第18号车站(从0开始编号)。
  • 到站时间:Unix时间戳,精确到秒。
  • 开门方向:0x01表示左侧开门,0x02表示右侧开门。
  • 预留字段:为了后续扩展,先填0x00。

我个人习惯,所有多字节字段都采用大端序(Big-Endian)。为什么?因为网络字节序就是大端序,省得来回转换。你想想看,要是PIS用大端,TCMS用小端,那解析出来的数据全是乱的。

小技巧:在开发阶段,可以用Wireshark抓包验证报文。我每次写完协议解析代码,第一件事就是抓包看原始字节流,跟设计文档逐字节比对。这一步能发现90%的隐藏bug。

4.6 总结一下

好了,这一章的内容就这些。TCP/IP协议栈是PIS和TCMS通信的骨架,报文结构是血肉。记住三点:

  • 协议栈选TCP,端口固定5000-5005
  • 报文结构要包含帧头、长度、类型、序列号、时间戳、数据、校验、帧尾
  • 多字节字段统一用大端序

下一章,咱们聊聊具体的接口定义和信号映射。到时候我会拿一个实际项目的接口文档来拆解,保证干货满满。