OmniBinder — 让嵌入式多服务协作,回归一行代码的简单
面向 Linux / Windows(可扩展鸿蒙/Android) 多服务协作系统服务通信中间件(跨版/同板)
统一 IDL · Stub/Proxy 自动生成 · 同机 SHM 直通 · 跨板 TCP 自适应 · omni-cli 一键诊断
一、为什么会有 OmniBinder?
在嵌入式、工业和边缘计算场景中,一个完整系统从来不是一个单体程序。
一台工业机器人内部,传感器采集、运动规划、安全监控、日志记录是四个独立的服务进程;一座充电桩里,功率控制、计费结算、屏幕交互、温度监控分散在不同模块上;一辆工程机械的驾驶舱内,三块屏幕、一个数据融合单元、一个诊断接口各自运行在不同的控制器上。
每个场景都是多服务协作系统。 但现实是——没有统一的通信层。

协议碎片化:6 个服务,30 条自定义通道。每个服务各自定义一套通信协议,接口不统一,大量重复造轮子。
跨板调试困难:两块板子之间出了问题,日志只有原始的 hex 字节,没有结构化输出,定位一个跨板通信 Bug 动辄数小时。
服务状态不可见:一个服务挂了,其他服务不知道,开发者也发现不了——直到用户报告故障。没有心跳检测,没有死亡通知。
部署拓扑一变,代码就要重写:本地测试时 4 个服务跑在同一块板子上,共享内存工作得好好的。部署到生产环境,拆成两块板子——共享内存不通了,不得不把整层通信代码改成 TCP。下次再加一块板子,又要改一遍。
这就是我开发 OmniBinder 的原因。
二、OmniBinder 是什么?
OmniBinder 是一个面向嵌入式 Linux 与局域网分布式场景的服务通信中间件。它提供了一套统一的模型,让多个服务进程——无论在同设备、跨板、还是跨设备——以一致的方式完成注册、发现、RPC 调用、事件广播和状态感知。
一句话概括:OmniBinder 是在分布式服务之间充当通信桥梁的中间件,让服务与服务之间的连接、调用和数据分发标准化。

适用行业
| 场景 | 说明 |
|---|---|
| 工业机器人 | 传感器→算法→控制→安全→日志,同设备多板卡多服务协作 |
| 新能源充电桩 | 功率控制、计费结算、屏幕交互、温度监控,桩内多模块通信 |
| 工程机械 | 多屏联动、数据融合、远程诊断,驾驶舱内多控制器互联 |
| 车载智能座舱 | 中控屏、仪表盘、ADAS、娱乐系统,跨 ECU 域控制器通信 |
| 边缘计算网关 | 多个子设备数据的汇聚、转发、协议桥接,局域网服务网关 |
三、功能全览

| 维度 | 能力 |
|---|---|
| 接口定义 | 统一 .bidl IDL 语言,支持基础类型、结构体、数组、嵌套类型 |
| 代码生成 | C++ Stub(服务端骨架)+ C++ Proxy(客户端代理)+ C 接口 |
| 服务管理 | 注册 / 发现 / 注销,中心化 ServiceManager |
| 远程调用 | 同步 RPC(请求/响应)+ 单向调用(one-way) |
| 事件广播 | 发布/订阅 Topic 机制,一对多实时分发 |
| 死亡通知 | 服务异常退出时自动通知所有关注者 |
| 自动重连 | 服务恢复后自动重连,支持指数退避策略 |
| 传输自适应 | 同设备优先 SHM,跨设备走 TCP,零代码切换 |
| 诊断工具 | omni-cli 命令行,支持 list / info / call / watch 四个命令 |
| 跨平台 | Linux + Windows 双平台支持 |
| 零依赖 | C++11 编译,不依赖任何第三方库 |
四、运行时架构

控制面与数据面分离
OmniBinder 采用经典的两层架构:
-
ServiceManager(控制面):中心化的注册发现枢纽。所有服务启动时向它注册,客户端通过它发现目标服务。同时负责心跳监控、死亡通知和话题管理。
-
数据通道(数据面):服务之间直连通信。根据部署拓扑自动选择传输方式——
部署关系 传输方式 典型延迟 同设备(同一机器) 共享内存 (SHM) 68 μs 跨板(同一局域网) TCP 200-500 μs 切换方式 自动,零代码改动 —
omni-cli:运行时诊断工具
四个命令覆盖日常运维:
$ omni-cli list
NAME HOST PORT STATUS
SensorService 127.0.0.1 8097 ONLINE
AlgoService 127.0.0.1 8100 ONLINE
Total: 2 services online
$ omni-cli info SensorService
Service: SensorService
Host: 127.0.0.1
Port: 8097
Status: ONLINE
Interface: ISensor (id=0x10000001)
Methods:
- GetLatestData() -> SensorData (id=0x00000001)
- SetThreshold(ControlCommand) -> Status (id=0x00000002)
$ omni-cli call SensorService GetLatestData
Calling SensorService.GetLatestData() ...
interface_id = 0x10000001
method_id = 0x00000001
Response (status=OK, 38 bytes, 0.81 ms):
{ "sensor_id": 1, "temperature": 23.55, "humidity": 61.95, "location": "Room-A" }
$ omni-cli watch SensorService
Watching diagnostic data from SensorService...
[Diagnostic] invoke ISensor::GetLatestData seq=1042 direction=REQUEST
[Diagnostic] invoke ISensor::GetLatestData seq=1042 direction=REPLY
一行命令,看清所有服务状态与调用链路,无需重启,无需额外部署。
五、开发体验

第一步:定义接口(.bidl IDL 文件)
package demo;
struct SensorData {
int32 sensor_id;
float64 temperature;
float64 humidity;
string location;
}
service SensorService {
SensorData GetLatestData();
Status SetThreshold(ControlCommand cmd);
int32 GetSensorCount();
publishes SensorUpdate;
}
第二步:自动生成代码
$ ./omni-idlc sensor.bidl --lang cpp --outdir gen/
✓ sensor.bidl.h # 类型定义
✓ SensorServiceStub # 服务端骨架
✓ SensorServiceProxy # 客户端代理
第三步:写业务逻辑
服务端——继承自动生成的 Stub,实现接口即可:
class MyService : public SensorServiceStub {
SensorData GetLatestData() override { return readSensor(); }
};
runtime.registerService(&service); // 一行注册
runtime.publishTopic("SensorUpdate"); // 一行发布话题
客户端——使用自动生成的 Proxy:
SensorServiceProxy proxy(runtime);
proxy.connect(); // 一行连接
proxy.GetLatestData(&data); // 一行 RPC 调用
proxy.SubscribeSensorUpdate(callback); // 一行订阅广播
proxy.OnServiceDied([]{ reconnect(); }); // 一行死亡通知
从 IDL 定义到跑通第一个 RPC,只需三步。同设备自动走 SHM,跨板自动走 TCP——零代码切换。
六、服务协作关系

在一个典型的嵌入式系统中,服务不是孤立存在的。以上图为例——核心算法服务作为中枢,接收视频、语音、人脸、CAN 数据四个上游服务的输入,处理后输出到 HMI 服务展示;电源管理服务监控所有服务的功耗;升级服务负责所有服务的固件 OTA 更新。
通过 omni-cli,你可以随时查看任意服务的心跳状态、接口定义、调用链路和实时诊断数据流。
七、性能数据
| 测试项 | 样本数 | 平均值 | P95 | P99 |
|---|---|---|---|---|
| RPC Echo (0 bytes) | 1000 | 68.5 μs | 85 μs | 101 μs |
| RPC Echo (256 bytes) | 1000 | 68.3 μs | 86 μs | 110 μs |
| RPC Echo (1024 bytes) | 1000 | 70.5 μs | 89 μs | 109 μs |
| RPC Echo (4096 bytes) | 1000 | 74.2 μs | 97 μs | 122 μs |
| RPC Echo (8192 bytes) | 1000 | 86.4 μs | 111 μs | 138 μs |
| RPC Add (2 x int32) | 1000 | 73.6 μs | 93 μs | 109 μs |
| Topic pub/sub (64 bytes) | 1000 | 28.4 μs | 52 μs | 69 μs |
| Topic pub/sub (8192 bytes) | 1000 | 38.6 μs | 64 μs | 84 μs |
测试环境:Windows WSL2 Ubuntu 20.04 · SHM eventfd 事件驱动 · 1000 轮 · 预热 50 轮 · 100% 成功率。
八、快速上手
# 编译
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)
# 启动 ServiceManager
./build/target/bin/service_manager
# 启动服务端
./build/target/example/example_cpp_sensor_server
# 启动客户端
./build/target/example/example_cpp_sensor_client
九、开源与许可
- 开源地址:github.com/TaoistLuo/OmniBinder
- 许可协议:MIT
- 编译标准:C++11,同时提供完整 C 接口
- 支持平台:Linux(epoll/eventfd/SHM)+ Windows(IOCP/Named Pipe)
- 外部依赖:零
如果你正在构建一个由多个服务组成的嵌入式或分布式系统,希望它们之间有一层统一的通信桥梁——OmniBinder 就是为此设计的。


571

被折叠的 条评论
为什么被折叠?



