背景
自Java语言流行以来,其主打的面向对象编程也成为了家喻户晓的一种程序设计思想:
“封装、继承、多态”、“易维护、易复用、易扩展”,“解耦、隔离”
而以过程为中心的“面向过程编程”,通常会优先分析出解决问题所需的步骤,然后用函数依次实现这些步骤,最后串联起来依次调用即可,是一种基于顺序的思维方式。
常见的支持面向过程的编程语言有 C语言、COBOL 语言等,被广泛的应用在系统内核、IoT、物联网等领域。其中一个比较典型的案例是串口通信协议的集成开发(驱动、SDK),虽然大多数的Web应用都已经跨入了“Json Free”的时代,但大量的嵌入式设备使用仍是串口协议,以获得能耗、体积和效率等方面的优势。而现有的驱动大多由C,使用面向过程的方式编写的。
举个栗子🌰 ,当我们的应用需要提供线下的服务:用户在门户店可以使用一体机访问我们的服务,可以选择使用线下POS机进行刷卡支付(类比肯德基)。我们不仅要在网页后台计算出订单价格,还要通知POS机开始“接单”,完成刷卡操作并及时返回交易数据。
然而,当打开POS机“附赠”的接口文档时,晃眼的二进制案例、复杂的数据结构却让我们手足无措 —— 所有的数据都需要通过那根RS232串口线,以“01010101”的数据与相连的一体机进行交互。
PS:一体机是一台Windows物理机,通过COM接口(RS232、9针线)连接POS机设备
令人头晕的二进制
不同于我们日常所使用的HTTP协议:
- 具有标准的报文结构和数据编码
- 完备的SDK和生态链工具,可以很容易实现CS(Client-Server)架构的数据传输
- 无需关注应用层(ISO Application Layer)以下的技术细节
而串口更贴近于ISO的物理层:通过指定频率(Baud 波特率)的高低电平(0/1)来传输数据。
因此要想通过串口传递具有特定意义的数据时,通常需要对二进制数据加以区分、组合、编码,以赋予其表达复杂数据结构的能力 —— 串口通信协议。例如一个典型(但又稍显复杂)的串口协议报文:
一个串口消息的数据结构(使用16进制表示字节流示例)
串=“串行”,数据在传输过程中都是按顺序写入、读出的,因此需要准确的告诉服务方:
- StartToken / EndToken,标记当前消息何时开始何时结束
- Length,当前欲读取的数据长度
为了提升协议的易用性,将不同目的的数据通过类型加以区分,具有不同的序列化规则
- Hex(十六进制)
- BCD(二进制化整数)
- ASC(ASIIC码)
数据部分则由消息头和多组消息数据组成
- 关键字段(如ID、Code、Version)都是固定类型、固定长度的数据
- 而数据字段(Data)在不同的Field Code(不同场景下)是不同的
- 是一个变长数据