系统版本和环境配置
系统版本:ubuntu-18.04.6-live-server-amd64版本系统镜像
环境配置:
sudo apt-get update
sudo apt-get upgrade
sudo apt install build-essential
sudo apt-get install dbus
sudo apt-get install d-feet # 用于查看 session bus 和 system bus
sudo apt-get install libdbus-1-dev
sudo apt-get install libgtk2.0-dev
sudo apt-get install libdbus-glib-1-dev # C和glib下的dbus api库
# 运行 dbus-send 和 dbus-monitor 命令,根据系统提示进行安装
官方文档信息:
-
D-Bus 官网,有些比较好的tutorial https://www.freedesktop.org/wiki/Software/dbus/
-
D-Bus low-level public API https://dbus.freedesktop.org/doc/api/html/group__DBus.html
-
同上,附带一定中文信息 https://www.cnblogs.com/DXGG-Bond/p/13092761.html
-
D-Bus Glib bindings API https://dbus.freedesktop.org/doc/dbus-glib/
该文档下载链接(有图片显示问题):
https://files.cnblogs.com/files/tlam/D-BUS基本使用学习【low-level_C_API】.zip
可能遇到的问题和疑问
- 针对编译过程中可能出现的错误:
https://blog.csdn.net/zfzf294990051/article/details/6303425
- system bus和session bus的区别:
https://www.cnblogs.com/cnland/archive/2013/04/28/3049281.html
- 如果有安装notification-daemon进行监听的需求:
或者存在如 The name org.freedesktop.Notifications was not provided by any .service files 的问题
https://zoomadmin.com/HowToInstall/UbuntuPackage/notification-daemon
https://wiki.archlinux.org/title/Desktop_notifications#Standalone
- dbus-monitor: unable to enable new-style monitoring 无法监控
ubuntu环境下,dbus-monitor默认禁止监视系统总线,请尝试使用sudo权限运行dbus-monitor命令。
- 如何去理解dbus-monitor的数据结果:
https://askubuntu.com/questions/38733/how-to-read-dbus-monitor-output
- 系统DBUS自带一些method,其官方文档:
https://dbus.freedesktop.org/doc/dbus-java/api/org/freedesktop/DBus.html
- 编译本文档中的代码:
g++ dbus_learn2.cpp -std=c++0x $(pkg-config dbus-1 --cflags) -ldbus-1 -Werror -Wall -Wextra
- dbus method call over tcp 相关资料,未经可行性实践:
https://stackoverflow.com/questions/10158684/connecting-to-dbus-over-tcp
https://stackoverflow.com/questions/45484655/connect-to-dbus-service-via-tcp
- dbus 数据绑定相关资料:
https://blog.csdn.net/shanzhizi/article/details/7710692
D-BUS通信编程例子
对具体编程实例中的方法简单介绍,想要具体了解所有内容,请查阅官方文档。
信号signal发送
dbus_message_new_signal
方法:初始化并返回一个signal类型的DbusMessagedbus_message_iter_init_append
方法和dbus_message_iter_append_basic
方法:分别对迭代器类型DBusMessageIter进行 初始化绑定到对应的DbusMessage 和 添加基础数据到相应的内存空间dbus_connection_send
方法:将对应的DbusMessage发送到消息队列,带回消息队列的serial数据dbus_connection_flush
方法:清空dbus消息队列,立即发送
示例程序:
dbus_uint32_t serial = 0; // unique number to associate replies with requests
DBusMessage* bus_msg;
DBusMessageIter bus_args;
void* sigvalue = (void*)("hello qiujunyin");
//object name / interface name / name of the signal
bus_msg = dbus_message_new_signal("/test/signal/Object","test.signal.Type","Test");
if (bus_msg==NULL){
cout<<"dbus signale message is null"<<endl;
exit(1);
}
// 初始化参数迭代器并append进入signal信息
dbus_message_iter_init_append(bus_msg,&bus_args);
if (!dbus_message_iter_append_basic(&bus_args, DBUS_TYPE_STRING, &sigvalue)) {
cout<<"dbus iter append fail : out of memory"<<endl;
exit(1);
}
//发送signal serial带回其在消息队列中的位置
if (!dbus_connection_send(bus_conn,bus_msg,&serial)){
cout<<"dbus send signal fail : out of memory"<<endl;
exit(1);
}
cout<<"signal serial in mq :"<<serial<<endl;
dbus_connection_flush(bus_conn);
dbus_message_unref(bus_msg);
dbus-monitor监控:
开启dbus-monitor监控后,编译运行上述代码可以观察得到:
dbus-monitor --session --monitor "type=signal,interface=test.signal.Type"
同步method_call
dbus_message_new_method_call
方法:初始化并返回一个method_call类型的DbusMessagedbus_connection_send_with_reply_and_block
方法:阻塞方式发送DbusMessage,等待返回数据dbus_message_get_args
方法:对DbusMessage中的对应参数数据解析获取dbus_message_unref
方法:释放DbusMessage资源,减少引用技术
示例代码:
//5. 同步method_call dbus_connection_send_with_reply_and_block
DBusMessage * dbus_reply = nullptr;
const char * dbus_result = nullptr;
bus_msg = dbus_message_new_method_call("org.freedesktop.DBus","/","org.freedesktop.DBus.Introspectable","Introspect");
if (bus_msg == NULL){
cout<<"dbus method call is null"<<endl;
exit(1);
}
// 增加入参:a. dbusMessage绑定迭代器原始操作接口 b. dbus_message_append_args
// const char *v_STRING = "input args test";
// if (!dbus_message_append_args(bus_msg,DBUS_TYPE_STRING,&v_STRING,DBUS_TYPE_INVALID)){
// cout<<"dbus method call append args failed"<<endl;
// exit(1);
// }
dbus_reply = ::dbus_connection_send_with_reply_and_block(bus_conn, bus_msg, DBUS_TIMEOUT_USE_DEFAULT, &bus_err); //无限时长阻塞
if (dbus_reply == NULL){
//如果有入参,预期此处调用失败,此method call为系统dbus提供返回,无需入参。报错多余入参
cout<<"dbus method call return fail : "<<bus_err.name<<" "<<bus_err.message<<endl;
exit(1);
}
if (!dbus_message_get_args(dbus_reply,&bus_err,DBUS_TYPE_STRING,&dbus_result,DBUS_TYPE_INVALID)){
cout<<"dbus method call return parser failed : "<<bus_err.name<<" "<<bus_err.message<<endl;
exit(1);
}else{
cout<<"dbue method call result : "<<dbus_result<<endl;
}
dbus_message_unref(bus_msg);
dbus_message_unref(dbus_reply);
此段代码同步调用了系统dbus的相关方法:org.freedesktop.DBus.Introspectable下的Introspect方法,返回官方文档数据字符串。

异步method_call
- dbus_connection_send_with_reply方法:非阻塞方式下发送DbusMessage,函数调用结果仅代表是否发送成功,具体数据将会被存储在DBusPendingCall类型的数据下。
- dbus_pending_call_block方法:阻塞等待DBusPendingCall数据回调
- dbus_pending_call_steal_reply方法:将DBusPendingCall数据转换为DbusMessage数据用于后续使用
示例程序:
DBusPendingCall* bus_pending;
DBusMessageIter bus_args2;
void *param = (void*)("");
void *stat = new int;
bus_msg = dbus_message_new_method_call("test.method.server","/test/method/Object","test.method.Type","Method");
if (bus_msg == NULL){
cout<<"dbus method call is null"<<endl;\
exit(1);
}
dbus_message_iter_init_append(bus_msg,&bus_args2);
if (!dbus_message_iter_append_basic(&bus_args2, DBUS_TYPE_STRING, ¶m)) {
cout<<"dbus iter append fail : out of memory"<<endl;
exit(1);
}
if (!dbus_connection_send_with_reply(bus_conn, bus_msg, &bus_pending, 1000)) { // -1 is default timeout
cout<<"dbus send method call : out of memory"<<endl;
exit(1);
}
if (bus_pending==NULL){
cout<<"dbus method call' Pending is NULL"<<endl;
exit(1);
}else{
cout<<"dbus method call' Pending address : "<<bus_pending<<endl;
}
dbus_connection_flush(bus_conn);
dbus_message_unref(bus_msg);
dbus_pending_call_block(bus_pending); //在上述时间限制内,阻塞等待返回数据,去除则完全异步
bus_msg = dbus_pending_call_steal_reply(bus_pending); //返回数据转换
if (bus_msg == NULL) {
cout<<"dbus method call reply NULL"<<endl;
exit(1);
}
dbus_pending_call_unref(bus_pending); //释放返回数据的句柄
if(!dbus_message_iter_init(bus_msg,&bus_args)){
//获取转换后数据的迭代器
cout<<"dbus method call reply message has no argument"<<endl;
exit(1);
}
else{
dbus_message_iter_get_basic(&bus_args, stat);
}
cout<<"dbus method call reply value : "<<*((int*)stat)<<endl;
dbus_message_unref(bus_msg);
接受signal信号
- dbus_bus_add_match方法:dbus将接受特定来源的信号数据,此方法为其添加匹配规则,默认会接受来源系统默认dbus的信号。
- dbus_connection_read_write方法:非阻塞方式去查看该连接是否可读写
- dbus_message_is_signal方法:判断DbusMessage数据的类型是否为signal
示例程序:
dbus_error_init(&bus_err);
dbus_bus_add_match(bus_conn,"type='signal',interface='com.example'",&bus_err); //默认对session dbus也监听了
dbus_connection_flush(bus_conn);
if (dbus_error_is_set(&bus_err)){
cout<<"dbus add match fail : "<<bus_err.message<<endl;
exit(1);
}
while(1){
//非阻塞监听信号
dbus_connection_read_write(bus_conn, 0);
bus_msg = dbus_connection_pop_message(bus_conn);
if(bus_msg==NULL){
sleep(1);
continue;
}
//再次过滤
if(dbus_message_is_signal(bus_msg,"com.example","signal_name")){
if (!dbus_message_get_args(bus_msg,&bus_err,DBUS_TYPE_STRING,&dbus_result,DBUS_TYPE_INVALID)){
cout<<"dbus method call return parser failed : "<<bus_err.name<<" "<<bus_err.message<<endl;
exit(1);
}
cout<<"dbus get signal message : "<<dbus_result<<endl;
break;
}else{
// cout<<"dbus message interface : "<<dbus_message_get_interface(bus_msg)<<endl;
// cout<<"dbus message member : "<<dbus_message_get_member(bus_msg)<<endl;
cout<<"dbus check signal message and pass this signal"<<endl;
}
dbus_message_unref(bus_msg);
}
dbus-send命令模拟发送信号:
dbus-send --session --type=signal / com.example.signal_name string:"hello"
在上述程序编译运行后,运行dbus-send命令:

提供被远程调用的方法
- dbus_message_is_method_call方法:判断DbusMessage数据的类型是否为method_call
示例程序:
while(1){
//非阻塞监听信号
dbus_connection_read_write(bus_conn, 0);
bus_msg = dbus_connection_pop_message(bus_conn);
if(bus_msg==NULL){
sleep(1);
continue;
}
if(dbus_message_is_method_call(bus_msg,"test.method.Type","Method")){
reply_to_method_call(bus_conn,bus_msg);
break;
}
dbus_message_unref(bus_msg);
}
dbus-send命令进行调用:
dbus-send --session --type=method_call --print-reply --dest=test.method.server / test.method.Type.Method string:"hello"
获得我们程序中写入的返回数据
需要注意的事情
完整源代码
#include <dbus/dbus.h>
#include <cstddef>
#include <cstdio>
#include <iostream>
#include <unistd.h>
using namespace std;
void reply_to_method_call(DBusConnection* bus_conn,DBusMessage* bus_msg);
int main(){
DBusError bus_err;
DBusConnection* bus_conn;
//1. DBusError初始化
dbus_error_init(&bus_err);
//2. 连接DBUS
bus_conn = dbus_bus_get(DBUS_BUS_SESSION,&bus_err);
if (dbus_error_is_set(&bus_err)){
cout<<"Connection Error : "<<bus_err.message<<endl;
dbus_error_free(&bus_err);
exit(1);
}else if(bus_conn == NULL){
cout<<"bus_conn is null"<<endl;
exit(1);
}
//3. 设置DBUS名称 or 注册一个BUS NAME
int ret = dbus_bus_request_name(bus_conn,"test.method.server",DBUS_NAME_FLAG_REPLACE_EXISTING,&bus_err);
if (dbus_error_is_set(&bus_err)){
cout<<"Connection Error : "<<bus_err.message<<endl;
dbus_error_free(&bus_err);
exit(1);
}else if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER){
cout<<"request dbus name return fail"<<endl;
exit(1);
}
//4. 信号发送
dbus_uint32_t serial = 0; // unique number to associate replies with requests
DBusMessage* bus_msg;
DBusMessageIter bus_args;
void* sigvalue = (void*)("hello qiujunyin");
//object name / interface name / name of the signal
bus_msg = dbus_message_new_signal("/test/signal/Object","test.signal.Type","Test");
if (bus_msg==NULL){
cout<<"dbus signale message is null"<<endl;
exit(1);
}
// 初始化参数迭代器并append进入signal信息
dbus_message_iter_init_append(bus_msg,&bus_args);
if (!dbus_message_iter_append_basic(&bus_args, DBUS_TYPE_STRING, &sigvalue)) {
cout<<"dbus iter append fail : out of memory"<<endl;
exit(1);
}
//发送signal serial带回其在消息队列中的位置
if (!dbus_connection_send(bus_conn,bus_msg,&serial)){
cout<<"dbus send signal fail : out of memory"<<endl;
exit(1);
}
cout<<"signal serial in mq :"<<serial<<endl;
dbus_connection_flush(bus_conn);
dbus_message_unref(bus_msg);
//5. 同步method_call dbus_connection_send_with_reply_and_block
DBusMessage * dbus_reply = nullptr;
const char * dbus_result = nullptr;
bus_msg = dbus_message_new_method_call("org.freedesktop.DBus","/","org.freedesktop.DBus.Introspectable","Introspect");
if (bus_msg == NULL){
cout<<"dbus method call is null"<<endl;
exit(1);
}
// 增加入参:a. dbusMessage绑定迭代器原始操作接口 b. dbus_message_append_args
// const char *v_STRING = "input args test";
// if (!dbus_message_append_args(bus_msg,DBUS_TYPE_STRING,&v_STRING,DBUS_TYPE_INVALID)){
// cout<<"dbus method call append args failed"<<endl;
// exit(1);
// }
dbus_reply = ::dbus_connection_send_with_reply_and_block(bus_conn, bus_msg, DBUS_TIMEOUT_USE_DEFAULT, &bus_err); //无限时长阻塞
if (dbus_reply == NULL){
//如果有入参,预期此处调用失败,此method call为系统dbus提供返回,无需入参。报错多余入参
cout<<"dbus method call return fail : "<<bus_err.name<<" "<<bus_err.message<<endl;
exit(1);
}
if (!dbus_message_get_args(dbus_reply,&bus_err,DBUS_TYPE_STRING,&dbus_result,DBUS_TYPE_INVALID)){
cout<<"dbus method call return parser failed : "<<bus_err.name<<" "<<bus_err.message<<endl;
exit(1);
}else{
cout<<"dbue method call result : "<<dbus_result<<endl;
}
dbus_message_unref(bus_msg);
dbus_message_unref(dbus_reply);
//6. 异步method_call : 通过迭代器处理输入输出数据
// 存在问题:异步下如何通过DBusPendingCall捕获错误信息
DBusPendingCall* bus_pending;
DBusMessageIter bus_args2;
void *param = (void*)("");
void *stat = new int;
bus_msg = dbus_message_new_method_call("test.method.server","/test/method/Object","test.method.Type","Method");
if (bus_msg == NULL){
cout<<"dbus method call is null"<<endl;\
exit(1);
}
dbus_message_iter_init_append(bus_msg,&bus_args2);
if (!dbus_message_iter_append_basic(&bus_args2, DBUS_TYPE_STRING, ¶m)) {
cout<<"dbus iter append fail : out of memory"<<endl;
exit(1);
}
if (!dbus_connection_send_with_reply(bus_conn, bus_msg, &bus_pending, 1000)) { // -1 is default timeout
cout<<"dbus send method call : out of memory"<<endl;
exit(1);
}
if (bus_pending==NULL){
cout<<"dbus method call' Pending is NULL"<<endl;
exit(1);
}else{
cout<<"dbus method call' Pending address : "<<bus_pending<<endl;
}
dbus_connection_flush(bus_conn);
dbus_message_unref(bus_msg);
dbus_pending_call_block(bus_pending); //在上述时间限制内,阻塞等待返回数据,去除则完全异步
bus_msg = dbus_pending_call_steal_reply(bus_pending); //返回数据转换
if (bus_msg == NULL) {
cout<<"dbus method call reply NULL"<<endl;
exit(1);
}
dbus_pending_call_unref(bus_pending); //释放返回数据的句柄
if(!dbus_message_iter_init(bus_msg,&bus_args)){
//获取转换后数据的迭代器
cout<<"dbus method call reply message has no argument"<<endl;
exit(1);
}
else{
dbus_message_iter_get_basic(&bus_args, stat);
}
cout<<"dbus method call reply value : "<<*((int*)stat)<<endl;
dbus_message_unref(bus_msg);
//7. 接受信号
dbus_error_init(&bus_err);
dbus_bus_add_match(bus_conn,"type='signal',interface='com.example'",&bus_err); //默认对session dbus也监听了
dbus_connection_flush(bus_conn);
if (dbus_error_is_set(&bus_err)){
cout<<"dbus add match fail : "<<bus_err.message<<endl;
exit(1);
}
while(1){
//非阻塞监听信号
dbus_connection_read_write(bus_conn, 0);
bus_msg = dbus_connection_pop_message(bus_conn);
if(bus_msg==NULL){
sleep(1);
continue;
}
//再次过滤
if(dbus_message_is_signal(bus_msg,"com.example","signal_name")){
if (!dbus_message_get_args(bus_msg,&bus_err,DBUS_TYPE_STRING,&dbus_result,DBUS_TYPE_INVALID)){
cout<<"dbus method call return parser failed : "<<bus_err.name<<" "<<bus_err.message<<endl;
exit(1);
}
cout<<"dbus get signal message : "<<dbus_result<<endl;
break;
}else{
// cout<<"dbus message interface : "<<dbus_message_get_interface(bus_msg)<<endl;
// cout<<"dbus message member : "<<dbus_message_get_member(bus_msg)<<endl;
cout<<"dbus check signal message and pass this signal"<<endl;
}
dbus_message_unref(bus_msg);
}
//8. 提供被远程调用的方法
while(1){
//非阻塞监听信号
dbus_connection_read_write(bus_conn, 0);
bus_msg = dbus_connection_pop_message(bus_conn);
if(bus_msg==NULL){
sleep(1);
continue;
}
if(dbus_message_is_method_call(bus_msg,"test.method.Type","Method")){
reply_to_method_call(bus_conn,bus_msg);
break;
}
dbus_message_unref(bus_msg);
}
//9. 通过网络的DBUS方式
// 释放DBUS连接 (和dbus_connection_close 的区别)
dbus_connection_unref(bus_conn);
delete[] (char*)stat;
cout<<"All succeed"<<endl;
return 0;
}
void reply_to_method_call(DBusConnection* bus_conn,DBusMessage* bus_msg){
DBusMessage* reply;
DBusMessageIter args;
char* param = nullptr;
dbus_uint32_t level = 21614;
dbus_uint32_t serial = 0;
//读取参数
if (!dbus_message_iter_init(bus_msg, &args)){
cout<<"dbus method call :Message has no arguments"<<endl;
return;
}
else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)){
cout<<"dbus method call :Argument is not string"<<endl;
return;
}else{
dbus_message_iter_get_basic(&args, ¶m);
cout<<"dbus method call get argument : "<<param<<endl;
}
//创建返回
reply = dbus_message_new_method_return(bus_msg);
//添加返回数据
dbus_message_iter_init_append(reply, &args);
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &level)) {
cout<<"dbus method call append data:Out Of Memory"<<endl;
return;
}
//发送返回
if (!dbus_connection_send(bus_conn, reply, &serial)) {
cout<<"dbus method call send :Out Of Memory"<<endl;
return;
}
dbus_connection_flush(bus_conn);
dbus_message_unref(reply);
}