2、发布订阅模式基础:什么是发布订阅模式、与请求响应模式的区别、核心角色(Publisher、Subscriber、Event)

2.1 先聊聊:为什么需要发布订阅模式?

做车载通信这些年,我经常被问到这样一个问题:

「老张,我车上有几十个ECU,每个都要实时知道车速、转向角、刹车状态。如果都用请求响应,那网络不就炸了吗?」

问得好。你想想看,如果每个需要车速的节点都去问「车速多少?」,那每秒得产生多少请求?

嗯,这就是发布订阅模式诞生的原因。

一句话总结:发布订阅模式,就是「谁生产数据谁发布,谁需要数据谁订阅」。数据生产者不用关心谁在收,数据消费者也不用关心谁在发。

2.2 发布订阅 vs 请求响应:到底差在哪?

我刚开始做SOME/IP时,也经常把这两个搞混。后来在项目中踩过一次坑,才彻底分清楚。

咱们直接看对比:

对比维度 请求响应模式 发布订阅模式
通信方向 点对点(Client→Server→Client) 一对多(Publisher→多个Subscriber)
触发方式 由Client主动发起 由Publisher主动推送
数据流向 请求→响应,一问一答 发布→订阅,持续推送
典型场景 读取某个传感器的当前值 实时获取车速、转向角等周期性数据
网络负载 请求多时负载高 一次发布,多人接收,效率高
实时性 取决于请求频率 Publisher主动推送,延迟低

说白了,请求响应就像你打电话问朋友「现在几点了?」——每次都要拨号、等待、挂断。而发布订阅就像你订阅了一个天气预报公众号,每天自动推送,不用你主动去问。

我个人习惯:在项目中,如果数据是「状态类」的(比如车速、温度、位置),我优先用发布订阅。如果是「操作类」的(比如打开车门、设置参数),我优先用请求响应。

2.3 三个核心角色:Publisher、Subscriber、Event

发布订阅模式里,只有三个角色。不多不少,刚刚好。

2.3.1 Publisher(发布者)

Publisher就是数据的生产者。它负责:

  • 定义Event(事件)
  • 在合适的时机发布Event
  • 管理Subscriber的订阅关系

我记得有一次做ADAS项目,摄像头模块就是Publisher。它每30毫秒发布一次车道线检测结果。所有需要这个数据的模块——比如车道保持、自适应巡航——都来订阅它。

代码示例(伪代码):

// Publisher端
class LaneDetectionPublisher {
    Event laneEvent;  // 定义事件
    
    void publishLaneData() {
        LaneData data = detectLane();
        // 发布事件,所有订阅者都会收到
        SOMEIP_Publish(laneEvent, data);
    }
}

2.3.2 Subscriber(订阅者)

Subscriber就是数据的消费者。它负责:

  • 向Publisher发起订阅请求
  • 接收Publisher推送的Event数据
  • 处理接收到的数据

这里有个坑,我曾经踩过:

我曾经在项目中遇到:某个Subscriber订阅了Event,但忘记处理数据。结果Publisher一直发,Subscriber一直收,但数据没人用,白白浪费带宽。所以,订阅之前一定要想清楚——你真的需要这个数据吗?

代码示例:

// Subscriber端
class LaneKeepAssist {
    void subscribeToLaneData() {
        // 订阅车道线事件
        SOMEIP_Subscribe(laneEvent, onLaneDataReceived);
    }
    
    void onLaneDataReceived(LaneData data) {
        // 处理接收到的数据
        adjustSteering(data);
    }
}

2.3.3 Event(事件)

Event是发布订阅模式的核心载体。它定义了:

  • 数据的类型(比如int32、float、结构体)
  • 数据的ID(唯一标识)
  • 数据的生命周期(比如周期性发布、变化时发布)

在SOME/IP协议里,Event有几种发布方式:

发布方式 说明 适用场景
周期性发布 每隔固定时间发布一次 车速、转速等周期性信号
变化时发布 数据变化超过阈值时才发布 温度、压力等变化不频繁的信号
事件触发发布 特定事件发生时发布 故障码、报警信号

避坑指南:Event的ID一定要全局唯一。我见过一个项目,两个Publisher用了相同的Event ID,结果Subscriber收到了错误的数据,排查了整整两天。嗯,从那以后,我每次设计Event ID都会画一张全局分配表。

2.4 发布订阅的完整流程

咱们走一遍完整的流程,你就全明白了:

  1. Publisher启动:先注册自己的Event,告诉网络「我有这些数据可以发布」
  2. Subscriber发起订阅:Subscriber向Publisher发送订阅请求,说「我要订阅这个Event」
  3. Publisher确认订阅:Publisher收到请求后,把Subscriber加入订阅列表
  4. Publisher发布数据:当数据准备好时,Publisher把数据推送给所有订阅者
  5. Subscriber接收数据:Subscriber收到数据后,调用回调函数处理
  6. Subscriber取消订阅:当不再需要数据时,Subscriber可以主动取消订阅

这个流程看起来简单,但实际项目中要考虑的东西很多。比如:

  • 如果Subscriber订阅时,Publisher还没启动怎么办?
  • 如果Publisher挂了,Subscriber怎么知道?
  • 如果网络延迟高,数据过期了怎么办?

这些问题,咱们后面的章节会一一解答。今天先把基础打牢。

2.5 小结

发布订阅模式,说白了就是「你发我收,互不干扰」。它和请求响应的最大区别在于:

  • 请求响应是「你问我答」,适合操作类场景
  • 发布订阅是「你发我收」,适合状态类场景

三个核心角色:

  • Publisher:数据生产者,负责发布Event
  • Subscriber:数据消费者,负责订阅Event
  • Event:数据载体,定义了数据的类型、ID和发布方式

我的建议:刚开始学SOME/IP时,先把这个模式理解透。后面的服务发现、网络绑定、序列化,都是建立在这个基础之上的。地基打不牢,后面盖楼会歪的。

下一章,咱们聊聊SOME/IP的Event是如何定义的,以及怎么在代码里实现一个完整的发布订阅流程。