当前位置: 首页 > news >正文

DBus总线详解

        DBus(Desktop Bus)是一种用于进程间通信(IPC)的系统总线,广泛应用于Linux环境中的桌面应用程序和系统进程之间的消息传递。它允许不同的应用程序和服务相互通信,无论是运行在同一台机器上的本地进程,还是通过网络连接的远程进程。

1. DBus的基本概念

DBus是一种消息总线系统,主要用于处理消息的发送和接收。DBus支持两种通信方式:

  • 系统总线(System Bus):通常用于系统级服务之间的通信,例如硬件管理、系统监控等,路径通常为 /var/run/dbus/system_bus_socket
  • 会话总线(Session Bus):通常用于同一会话中的应用程序之间的通信,适用于桌面应用程序和用户级服务之间的通信,通过 dbus-launch 启动。

DBus的核心特性是它的发布-订阅模式,允许进程间通过“对象”和“方法”进行通信。

2. DBus的通信机制

DBus的通信是基于消息的,每条消息通常由以下几个部分组成:

  • 消息类型:指定消息的类型,常见的有请求、响应、事件等。
  • 目标对象:指定消息的接收对象,每个DBus对象都有一个唯一的路径。
  • 方法名称:指定消息要调用的具体方法。
  • 参数:传递给方法的参数。
  • 返回值:方法调用后的响应。

3. DBus的工作方式

DBus通信是通过客户端和服务器模型进行的:

  • 客户端:发起消息的进程。
  • 服务端:接收并响应消息的进程。

客户端通过DBus API发送消息,消息通过总线传递给目标服务进程。目标服务进程接收到消息后进行处理,并返回响应。如果消息没有返回,客户端可能会继续等待,直到超时。

4. DBus的主要组件

  • DBus守护进程(DBus Daemon):DBus通信的核心,负责处理所有的消息传输。它运行在后台,负责维护总线、消息路由、权限控制等。
  • 接口(Interface):在DBus中,每个对象都可以提供一组接口,接口定义了该对象可以提供的方法和信号。接口类似于面向对象编程中的接口(interface),它定义了通信的约定。
  • 对象(Object):DBus中的对象代表了一种服务或功能,类似于面向对象编程中的类实例。每个对象有一个唯一的路径标识符。
  • 信号(Signal):信号是对象发送的通知消息,用于告知其他进程某些事件的发生。

5. DBus的消息类型

DBus支持多种消息类型,常见的有:

  • 方法调用(Method Call):客户端向服务端请求调用一个方法,通常带有参数,服务端会返回一个结果。
  • 方法返回(Method Return):服务端响应方法调用,并返回结果。
  • 错误(Error):发生错误时,服务端会发送错误消息。
  • 信号(Signal):服务端向客户端广播信号,通知事件的发生。

6. DBus的API

DBus提供了C语言的API供开发者使用,同时也有针对其他语言的绑定库(如Python、Java等)。常见的操作包括:

  • 连接到DBus:应用程序需要连接到DBus总线才能进行通信。
  • 发送消息:使用DBus API发送消息到指定对象。
  • 接收消息:应用程序可以注册回调函数来监听来自其他进程的消息。
  • 调用方法:发送消息请求远程进程执行特定的方法,并接收返回结果。
  • 监听信号:注册监听器,接收来自其他进程的广播信号。
//server.c#include <stdio.h>
#include <stdlib.h>
#include <dbus/dbus.h>// 前向声明消息处理函数
DBusHandlerResult handle_method_call(DBusConnection *connection, DBusMessage *message, void *user_data);int main() {DBusError error;DBusConnection *connection = NULL;// 初始化错误结构体dbus_error_init(&error);// 建立与DBus会话总线的连接connection = dbus_bus_get(DBUS_BUS_SESSION, &error);if (dbus_error_is_set(&error)) {fprintf(stderr, "连接DBus失败: %s\n", error.message);dbus_error_free(&error);return EXIT_FAILURE;}// 设置服务名称、对象路径和接口信息const char *service_name = "com.example.SampleService";const char *object_path = "/com/example/SampleObject";const char *interface_name = "com.example.SampleInterface";// 注册服务名称int request_name_result = dbus_bus_request_name(connection, service_name, DBUS_NAME_FLAG_REPLACE_EXISTING, &error);if (dbus_error_is_set(&error)) {fprintf(stderr, "注册DBus名称失败: %s\n", error.message);dbus_error_free(&error);dbus_connection_unref(connection);return EXIT_FAILURE;}if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {fprintf(stderr, "未能获取服务名称的所有权\n");dbus_connection_unref(connection);return EXIT_FAILURE;}// 创建并注册对象路径和消息处理函数DBusObjectPathVTable vtable = {.message_function = handle_method_call};dbus_connection_register_object_path(connection, object_path, &vtable, NULL);printf("DBus服务已启动,等待客户端请求...\n");// 主事件循环while (1) {// 处理所有挂起的消息dbus_connection_read_write_dispatch(connection, -1);}// 释放资源(实际上不会执行到这里,因为是无限循环)dbus_connection_unref(connection);dbus_error_free(&error);return EXIT_SUCCESS;
}// 消息处理函数实现
DBusHandlerResult handle_method_call(DBusConnection *connection, DBusMessage *message, void *user_data) {// 检查是否是方法调用消息if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_METHOD_CALL) {return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;}// 获取消息的接口和方法名称const char *interface_name = dbus_message_get_interface(message);const char *method_name = dbus_message_get_member(message);if (!interface_name || !method_name) {return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;}// 打印接收到的方法调用信息printf("接收到方法调用: %s.%s\n", interface_name, method_name);// 处理特定接口和方法if (strcmp(interface_name, "com.example.SampleInterface") == 0) {// 处理SampleMethod(字符串参数)if (strcmp(method_name, "SampleMethod") == 0) {DBusMessageIter args;if (dbus_message_iter_init(message, &args)) {char *str_arg = NULL;if (dbus_message_iter_get_arg_type(&args) == DBUS_TYPE_STRING) {dbus_message_iter_get_basic(&args, &str_arg);printf("收到字符串参数: %s\n", str_arg ? str_arg : "NULL");}}// 创建返回消息DBusMessage *reply = dbus_message_new_method_return(message);if (reply) {DBusMessageIter reply_iter;dbus_message_iter_init_append(reply, &reply_iter);const char *reply_str = "hi from server!";dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_STRING, &reply_str);dbus_connection_send(connection, reply, NULL);dbus_message_unref(reply);return DBUS_HANDLER_RESULT_HANDLED;}}// 处理SampleIntMethod(int参数)else if (strcmp(method_name, "SampleIntMethod") == 0) {DBusMessageIter args;if (dbus_message_iter_init(message, &args)) {int int_arg = 0;if (dbus_message_iter_get_arg_type(&args) == DBUS_TYPE_INT32) {dbus_message_iter_get_basic(&args, &int_arg);printf("收到整数参数: %d\n", int_arg);}}// 创建返回消息DBusMessage *reply = dbus_message_new_method_return(message);if (reply) {DBusMessageIter reply_iter;dbus_message_iter_init_append(reply, &reply_iter);// 返回整数的平方int result = 1314; // 示例返回值dbus_message_iter_append_basic(&reply_iter, DBUS_TYPE_INT32, &result);dbus_connection_send(connection, reply, NULL);dbus_message_unref(reply);return DBUS_HANDLER_RESULT_HANDLED;}}}return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}    
//client.c
#include <stdio.h>
#include <stdlib.h>
#include <dbus/dbus.h>int main() {DBusError error;DBusConnection *connection = NULL;DBusMessage *message = NULL;DBusMessage *reply = NULL;DBusMessageIter args;// 初始化错误结构体dbus_error_init(&error);// 建立与DBus会话总线的连接connection = dbus_bus_get(DBUS_BUS_SESSION, &error);if (dbus_error_is_set(&error)) {fprintf(stderr, "连接DBus失败: %s\n", error.message);dbus_error_free(&error);return EXIT_FAILURE;}// 设置服务名称、对象路径和接口信息const char *service_name = "com.example.SampleService";const char *object_path = "/com/example/SampleObject";const char *interface_name = "com.example.SampleInterface";printf("开始向服务端发送消息...\n");// 发送字符串消息{printf("发送字符串消息...\n");message = dbus_message_new_method_call(service_name, object_path, interface_name, "SampleMethod");if (message == NULL) {fprintf(stderr, "创建字符串消息失败\n");goto cleanup;}// 添加字符串参数dbus_message_iter_init_append(message, &args);const char *param = "Hello from client!";if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &param)) {fprintf(stderr, "添加字符串参数失败\n");dbus_message_unref(message);message = NULL;goto cleanup;}// 发送消息并获取响应reply = dbus_connection_send_with_reply_and_block(connection, message, 2000,  // 设置2秒超时&error);// 处理响应if (dbus_error_is_set(&error)) {fprintf(stderr, "发送字符串消息失败: %s\n", error.message);dbus_error_free(&error);} else if (reply != NULL) {DBusMessageIter reply_iter;if (dbus_message_iter_init(reply, &reply_iter) &&dbus_message_iter_get_arg_type(&reply_iter) == DBUS_TYPE_STRING) {char *reply_str = NULL;dbus_message_iter_get_basic(&reply_iter, &reply_str);if (reply_str) {printf("字符串消息响应: %s\n", reply_str);}}dbus_message_unref(reply);} else {fprintf(stderr, "未收到字符串消息响应\n");}dbus_message_unref(message);message = NULL;reply = NULL;}// 发送整数消息{printf("发送整数消息...\n");message = dbus_message_new_method_call(service_name, object_path, interface_name, "SampleIntMethod");if (message == NULL) {fprintf(stderr, "创建整数消息失败\n");goto cleanup;}// 添加整数参数dbus_message_iter_init_append(message, &args);int int_param = 520;if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &int_param)) {fprintf(stderr, "添加整数参数失败\n");dbus_message_unref(message);message = NULL;goto cleanup;}// 发送消息并获取响应reply = dbus_connection_send_with_reply_and_block(connection, message, 2000,  // 设置2秒超时&error);// 处理响应if (dbus_error_is_set(&error)) {fprintf(stderr, "发送整数消息失败: %s\n", error.message);dbus_error_free(&error);} else if (reply != NULL) {DBusMessageIter reply_iter;if (dbus_message_iter_init(reply, &reply_iter) &&dbus_message_iter_get_arg_type(&reply_iter) == DBUS_TYPE_INT32) {int reply_int = 0;dbus_message_iter_get_basic(&reply_iter, &reply_int);printf("整数消息响应: %d\n", reply_int);}dbus_message_unref(reply);} else {fprintf(stderr, "未收到整数消息响应\n");}dbus_message_unref(message);message = NULL;reply = NULL;}cleanup:// 释放资源if (reply != NULL) dbus_message_unref(reply);if (message != NULL) dbus_message_unref(message);if (connection != NULL) {dbus_connection_unref(connection);connection = NULL;}dbus_error_free(&error);printf("客户端已完成所有操作并退出\n");return EXIT_SUCCESS;
}    

觉得有帮助的话,打赏一下呗。。

           

群聊:

需要商务合作(定制程序)的欢迎私信!! 

相关文章:

  • c++ 拷贝构造函数
  • vue 中的ref属性
  • Grafana-Gauge仪表盘
  • git配置(1): 根据remote自动选择账号执行commit
  • 【掌握文件操作】(下):文件的顺序读写、文件的随机读写、文件读取结束的判定、文件缓冲区
  • C++异常处理机制
  • :inline=“true“会发生什么
  • 酒店用品源头厂家推荐
  • SQL中的锁机制
  • mybatis的mapper对应的xml写法
  • 如何解决网站服务器的异常问题?
  • Gin项目脚手架与标配组件
  • 网站服务器出现异常的原因是什么?
  • 回头看,FPGA+RK3576方案的功耗性能优势
  • 网站缓存入门与实战:浏览器与Nginx/Apache服务器端缓存,让网站速度起飞!(2025)
  • Nginx代理、缓存与Rewrite
  • 智能驾驶感知算法任务简介
  • 2025年渗透测试面试题总结-匿名[校招]安全工程师(甲方)(题目+回答)
  • Vim 中设置插入模式下输入中文
  • 【烧脑算法】定长滑动窗口:算法题中的“窗口”智慧
  • 设计网站平台/网页广告调词平台
  • 企业内部的网站系统/美国站外推广网站
  • 助孕网站优化推广/电商的运营模式有几种
  • 怎么查看网站是否做百度排名/北京seo百科
  • 行业自助建站/网站在线客服系统免费
  • 个域名的网站建设方案书/谷歌推广app