实验今天给大家分享一种在嵌入式开发过程中用到的 DBus 通信。
一、何为 DBus?
在 Linux 系统中,DBus 是进程间的隐形快递网络。它就像在系统里搭建了一套高速公路网:
• 守护进程(dbus-daemon)负责交通调度
• 进程通过虚拟地址(总线地址)相互寻址
• 数据包裹(message)精准投递,支持快递单号回执(同步返回)
DBus 工作流程示意图
二、四大核心要素解析
DBus 结构由四个要素组成,下面小哥类比了一下:
这四要素就能确保你的消息能准确送达目标对象的操作接口。
三、主辅进程的设计
1、业务场景
• 主进程(Control Center)
发送控制指令,如:"CHECK_STATUS"、"REBOOT"
等待辅助进程回复,同时获取辅助队列发过来的数据实时显示温度数据
• 辅助进程(Sensor Daemon)
接收主进程发送过来的指令并处理完后返回执行结果
每秒推送温度数据给主进程
2、通信蓝图
主辅进程通信流程图
采用双向通信机制:
🔹 同步方法调用:主进程下达指令后等待确认
🔹 异步信号发射:辅助进程主动推送数据流
四、一个 C 语言使用 Dbus 的代码案例
1、辅助进程实现(服务端)
// sensor_daemon.c
#include <dbus/dbus.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
DBusHandlerResult handle_control(DBusConnection* conn, DBusMessage* msg) {
//指令处理逻辑
if (dbus_message_is_method_call(msg, "com.example.Control", "Execute")) {
constchar* cmd;
dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &cmd, NULL);
// 处理不同指令
printf("[DAEMON] 收到指令: %s\n", cmd);
constchar* res = "DEFAULT_OK";
if (strcmp(cmd, "CHECK_STATUS") == 0) {
res = "STATUS_OK";
} elseif (strcmp(cmd, "REBOOT") == 0) {
res = "REBOOTING";
}
// 返回响应
DBusMessage* reply = dbus_message_new_method_return(msg);
dbus_message_append_args(reply, DBUS_TYPE_STRING, &res, NULL);
dbus_connection_send(conn, reply, NULL);
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
void send_temperature(DBusConnection* conn) {
//温度数据模拟
staticint temp = 25;
temp += rand()%3 - 1; // 波动模拟
DBusMessage* signal = dbus_message_new_signal(
"/com/example/Sensor",
"com.example.Sensor",
"TemperatureUpdate"
);
dbus_message_append_args(signal, DBUS_TYPE_INT32, &temp, NULL);
dbus_connection_send(conn, signal, NULL);
dbus_message_unref(signal);
}
int main() {
//连接初始化
DBusConnection* conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
dbus_bus_request_name(conn, "com.example.Sensor", 0, NULL);
//注册处理方法
dbus_connection_add_filter(conn, handle_control, NULL, NULL);
dbus_bus_add_match(conn, "type='method_call',interface='com.example.Control'", NULL);
//主循环
while(1) {
dbus_connection_read_write_dispatch(conn, 500); // 非阻塞轮询
send_temperature(); // 定时发送温度
sleep(1);
}
return0;
}
2、主进程实现(客户端)
// control_center.c
#include <dbus/dbus.h>
#include <stdio.h>
#include <string.h>
void monitor_temperature(DBusConnection* conn) {
//温度监控线程
dbus_bus_add_match(conn,
"type='signal',"
"interface='com.example.Sensor',"
"path='/com/example/Sensor'",
NULL
);
while(1) {
dbus_connection_read_write(conn, 0);
DBusMessage* msg = dbus_connection_pop_message(conn);
if(msg && dbus_message_is_signal(msg, "com.example.Sensor", "TemperatureUpdate")) {
int temp;
dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &temp, NULL);
printf("[监控] 当前温度: %d℃\n", temp);
}
if(msg) dbus_message_unref(msg);
}
}
void send_command(DBusConnection* conn, const char* cmd) {
//发送指令
DBusMessage* msg = dbus_message_new_method_call(
"com.example.Sensor",
"/com/example/Sensor",
"com.example.Control",
"Execute"
);
dbus_message_append_args(msg, DBUS_TYPE_STRING, &cmd, NULL);
//等待回复
DBusError err;
dbus_error_init(&err);
DBusMessage* reply = dbus_connection_send_with_reply_and_block(conn, msg, 1000, &err);
if(dbus_error_is_set(&err)) {
printf("[错误] 指令发送失败: %s\n", err.message);
} else {
constchar* result;
dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &result, NULL);
printf("[响应] %s\n", result);
}
dbus_message_unref(msg);
dbus_message_unref(reply);
}
int main() {
//初始化连接
DBusConnection* conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
//启动监控线程
pthread_t tid;
pthread_create(&tid, NULL, (void*)monitor_temperature, conn);
//控制指令交互
char cmd[64];
while(1) {
printf("输入指令 (或exit退出): ");
fgets(cmd, sizeof(cmd), stdin);
cmd[strcspn(cmd, "\n")] = 0;
if(strcmp(cmd, "exit") == 0) break;
send_command(conn, cmd);
}
return0;
}
3、实验演示
1️⃣ 编译运行
# 安装开发库
sudo apt install libdbus-1-dev -y
# 编译双端
gcc sensor_daemon.c -o sensor_daemon -ldbus-1
gcc control_center.c -o control_center -ldbus-1 -lpthread
# 终端1启动传感器守护进程
./sensor_daemon
# 终端2启动控制中心
./control_center
2️⃣ 操作示例
输入指令 (或exit退出): CHECK_STATUS
[响应] STATUS_OK
[监控] 当前温度: 25℃
输入指令 (或exit退出): REBOOT
[响应] REBOOTING
[监控] 当前温度: 24℃
而且 Dbus 调试功能也非常的完善,基本上把上面几个常用的 Dbus 接口函数搞清楚了,玩起来不难。
当然如果你调试 dbus 的时候比较麻烦,Linux 也提供了工具:
网络监控器数据:
dbus-monitor"interface=com.example.Sensor"
用于指令发送器
# 发送重启指令
dbus-send --session --dest=com.example.Sensor \
/com/example/Sensor \
com.example.Control.Execute \
string:"REBOOT"
END
来源:嵌入式专栏
推荐阅读
- 零内存泄漏!2KB高效实现事件驱动框架,推荐这款开源事件管理器——LwEVT
- 别再用传统方法解析串口协议啦!单片机高效开发妙招,自定义协议处理效率翻倍(附源码)
- 竟有可以从 AP 直接加载程序启动的 MCU!
- 嵌入式代码如何写才能方便移植?
欢迎大家点赞留言,更多 Arm 技术文章动态请关注极术社区嵌入式客栈专栏欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。