电子产业一站式赋能平台

PCB联盟网

搜索
查看: 9|回复: 0
收起左侧

嵌入式开发之 D-Bus 通信机制

[复制链接]

613

主题

613

帖子

7834

积分

高级会员

Rank: 5Rank: 5

积分
7834
发表于 7 天前 | 显示全部楼层 |阅读模式
关注+星标公众,不错过精彩内容转自 | 嵌入式情报局
实验今天给大家分享一种在嵌入式开发过程中用到的 DBus 通信。
一、何为DBus?
在Linux系统中,DBus是进程间的隐形快递网络。它就像在系统里搭建了一套高速公路网:
? 守护进程(dbus-daemon)负责交通调度
? 进程通过虚拟地址(总线地址)相互寻址
? 数据包裹(message)精准投递,支持快递单号回执(同步返回)

4i12zcl5wzn64051590857.png

4i12zcl5wzn64051590857.png

DBus工作流程示意图二、四大核心要素解析
DBus结构由四个要素组成,下面小哥类比了一下:
DBus要素作用编写规范服务名(Service)进程的唯一标识符,类似快递公司的客服电话。反向域名格式:com.example.delivery对象路径(Object)服务内部的分组标识,类似公司内部的部门编号(如 /销售部/华东区)。层级式路径:/com/example/warehouse接口(Interface)定义对象的能力清单,类似家电说明书中的功能目录。与服务名一致 + 功能描述com.example.delivery.PackageOp方法(Method)与信号(Signal)方法:同步操作指令,类似打电话让快递员上门取件(需等待回复)。信号:异步事件通知,类似快递员按门铃告知包裹已送达(无需回复)。ShipPackage这四要素就能确保你的消息能准确送达目标对象的操作接口。
三、主辅进程的设计
一、业务场景
? 主进程(Control Center)
发送控制指令,如:"CHECK_STATUS"、"REBOOT"
等待辅助进程回复,同时获取辅助队列发过来的数据实时显示温度数据
? 辅助进程(Sensor Daemon)
接收主进程发送过来的指令并处理完后返回执行结果
每秒推送温度数据给主进程
二、通信蓝图

mea10hc3l1l64051590957.png

mea10hc3l1l64051590957.png

主辅进程通信流程图采用双向通信机制:
?? 同步方法调用:主进程下达指令后等待确认
?? 异步信号发射:辅助进程主动推送数据流
四、一个C语言使用Dbus的代码案例 一、辅助进程实现(服务端)
// sensor_daemon.c
#include
#include
#include
#include
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
", 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;
}
二、主进程实现(客户端)
// control_center.c
#include
#include
#include
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℃
", 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
", err.message);
    } else {
        constchar* result;
        dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &result, NULL);
        printf("[响应] %s
", 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, "
")] = 0;
        
        if(strcmp(cmd, "exit") == 0) break;
        send_command(conn, cmd);
    }
   
    return0;
}
三、实验演示
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 ------------

m1yg0lbdnfr64051591057.gif

m1yg0lbdnfr64051591057.gif

●专栏《嵌入式工具●专栏《嵌入式开发》●专栏《Keil教程》●嵌入式专栏精选教程
关注公众号回复“加群”按规则加入技术交流群,回复“1024”查看更多内容。
点击“阅读原文”查看更多分享。
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


联系客服 关注微信 下载APP 返回顶部 返回列表