D-Bus是GNOME和KDE环境中广泛使用的进程间通信的软件,D-Bus允许用户做方法调用或者捕获从别的程序发送的信号,从而达到进程通信的目的。
简介
消息协议由 首部( header ) 和 主体( body ) 两部分组成。
header 的签名是固定的,值的含义也是固定的
header 的长度必须是8的整数倍,以便数据进行对齐
body 只有值,其签名在 header 中
body 的长度不需要为8的倍数
header 加 body 的总长度(包括对齐充填)不得超过128MiB
首部
header 的类型签名为 yyyyuua(yv) ,即 :
byte, byte, byte, byte, uint32, uint32, struct{byte, variant}[]
这些值具有以下含义
值 | 说明 |
---|---|
第一个byte | 字节序,'l’表示小端、'B’表示大端 |
第二个byte | 消息类型 |
第三个byte | 位标志的按位或 |
第四个byte | 协议版本,只能为1 |
第一个uint32 | 主体的长度(以字节为单位) |
第二个uint32 | 消息的序列号 |
结构体数组 | 首部字段数组,byte是字段标识,varaint是字段的值 |
类型 | 值 | 说明 |
---|---|---|
INVALID | 0 | 无效的类型,必须被忽略 |
METHOD_CALL | 1 | 方法调用 |
METHOD_RETURN | 2 | 方法调用的返回值 |
ERROR | 3 | 错误回复 |
SIGNAL | 4 | 信号发送 |
位标志
标志 | 值 | 说明 |
---|
NO_REPLY_EXPECTED | 0x01 |不需要返回值和错误
NO_AUTO_START| 0x02| 不自动启动接收方进程
ALLOW_INTERACTIVE_AUTHORIZATION 0x04 通知接收方调用者已准备好等待交互式授权,仅当非特权代码调用特权更大的方法,并且部署了允许进行交互式授权的授权框架时,此标志才有效。
字段名 | 字段标识 | 字段值类型 | 何时必填 | 说明 |
---|---|---|---|---|
INVALID | 0 | N/A | N/A | 无效 |
PATH | 1 | OBJECT_PATH | METHOD_CALL, SIGNAL | 对象路径 |
INTERFACE | 2 | STRING | SIGNAL | 被调用的接口或触发点信号 |
MEMBER | 3 | STRING | METHOD_CALL, SIGNAL | 方法或信号的名称 |
ERROR_NAME | 4 | STRING | ERROR | 发生的错误的名称 |
REPLY_SERIAL | 5 | UINT32 | ERROR, METHOD_RETURN | 答复的消息的序列号 |
DESTINATION | 6 | STRING | 非必填 | 此消息打算连接的目标的名称 |
SENDER | 7 | STRING | 非必填 | 发送方的唯一名称 |
SIGNATURE | 8 | SIGNATURE | 非必填 | body 的类型签名 |
UNIX_FDS | 9 | UINT32 | 非必填 | 带外数据中文件描述符的个数 |
主体
首部中已经确定了目标,且主体部分的类型签名也在首部字段的SIGNATURE中,因此主体只需要按照 封装格式封装数据即可。
例如调用 org.demo.Hbc.Speak(string msg) 方法,对象路径为 /org/demo/Hbc ,参数为 “hello world” ,不需要返回值,则整个消息如下(假设采用小端字节序):
// header
0x6c 0x01 0x01 0x01 // 'l' + METHOD_CALL + NO_REPLY_EXPECTED + 协议版本1
0x0f 0x00 0x00 0x00 // body长度为15字节
0x01 0x00 0x00 0x00 // 消息的序列号
0x01 0x00 0x00 0x00 // PATH的字段标识 + 充填0
0x0d 0x00 0x00 0x00 // string的长度为13
0x2f 0x6f 0x72 0x67 // "/org"
0x2f 0x64 0x65 0x6d // "/dem"
0x6f 0x2f 0x48 0x62 // " o/ Hb"
0x63 0x00 0x00 0x00 // "c" + 结尾0 + 充填0
0x02 0x00 0x00 0x00 // INTERFACE的字段标识 + 充填0
0x12 0x00 0x00 0x00 // string的长度为18
0x6f 0x72 0x67 0x2e // "org."
0x64 0x65 0x6d 0x6f // "demo"
0x2e 0x48 0x62 0x63 // ".Hbc"
0x2e 0x53 0x70 0x65 // ".Spe"
0x61 0x6b 0x00 0x00 // "ak" + 结尾0 + 充填0
0x03 0x00 0x00 0x00 // MEMBER的字段标识 + 充填0
0x05 0x00 0x00 0x00 // string的长度为5
0x53 0x70 0x65 0x61 // "Spea"
0x6b 0x00 0x00 0x00 // "k" + 结尾0 + 充填0
0x06 0x00 0x00 0x00 // DESTINATION的字段标识 + 充填0
0x04 0x00 0x00 0x00 // string的长度为4
0x3a 0x31 0x2e 0x30 // ":1.0" 这是假设的
0x00 0x00 0x00 0x00 // 结尾0 + 充填0
0x08 0x00 0x00 0x00 // SIGNATURE的字段标识 + 充填0
0x01 0x73 0x00 0x00 // signature的长度为1,值为"s" + 结尾0 + 充填0
// body
0x0b 0x00 0x00 0x00 // String长度为11字节
0x68 0x65 0x6c 0x6c // "hell"
0x6f 0x20 0x77 0x6f // "o wo"
0x72 0x6c 0x64 0x00 // "rld" + 结尾0
D-Bus是一套进程通信体系,它有以下几层:
1.libdbus库,提供给各个应用程序调用,使应用程序具有通信和数据交换的
能力,两个应用程序可以直接进行通信,就像是一条socket通道,两
个程序之间建立通道之后,就可以通讯了。
2.消息守护进程,在libdbus的基础上创建,可以管理多个应用程序之间的通
信。每个应用程序都和消息守护进程建立dbus的链接,然后由消息守
护进程进行消息的分派。
3.各种包装库,有libdbus-glib,libdbus-qt等等,目的是将dbus的底层api进
行一下封装。
流程:
关键的接口以及功能:
DBusConnection *dbus_bus_get (DBusBusType type, DBusError *error) /* 建立和总线的连接 */
int dbus_bus_request_name (DBusConnection *connection,
const char *name,
unsigned int flags,
DBusError *error) /* 注册连接名称 */
DBusMessage *dbus_message_new_signal (const char *path,
const char *iface,
const char *name) /* 创建信号类型消息*/
void dbus_message_iter_init_append ( DBusMessage *message,
DBusMessageIter *iter) /* 加入参数到信号 */
dbus_bool_t dbus_connection_send ( DBusConnection *connection,
DBusMessage *message,
dbus_uint32_t *serial) /* 发送信号到总线 */
void dbus_message_unref (DBusMessage *message) /* 释放消息 */
void dbus_bus_add_match ( DBusConnection *connection,
const char *rule,
DBusError *error) /* 请求获取调用消息 */
DBusMessage *dbus_connection_pop_message ( DBusConnection *connection) /* 从总线获取消息 */
dbus_bool_t dbus_message_is_method_call (DBusMessage *message,
const char *iface,
const char *method) /* 判定消息是方法调用 */
dbus_bool_t dbus_message_iter_init (DBusMessage *message,
DBusMessageIter *iter) /* 获取参数 */
DBusMessage *dbus_message_new_method_return (DBusMessage *method_call) /* 创建返回消息 */
void dbus_message_iter_init_append ( DBusMessage *message,
DBusMessageIter *iter) /* 在消息中填入参数 */
dbus_bool_t dbus_connection_send ( DBusConnection *connection,
DBusMessage *message,
dbus_uint32_t *serial) /* 发送返回消息 */
DBusMessage *dbus_message_new_method_call (const char *destination,
const char *path,
const char *iface,
const char *method) /* 创建一个函数调用消息 */
void dbus_message_iter_init_append (DBusMessage *message,
DBusMessageIter *iter) /* 为消息添加参数 */
dbus_bool_t dbus_connection_send_with_reply (DBusConnection *connection,
DBusMessage *message,
DBusPendingCall **pending_return,
int timeout_milliseconds) /* 发送消息 */
void dbus_pending_call_block (DBusPendingCall *pending) /* 阻塞等待返回值 */
DBusMessage *dbus_pending_call_steal_reply (DBusPendingCall *pending) /* 获得返回消息 */
dbus_bool_t dbus_message_iter_init (DBusMessage *message,
d-feet dbus-sender dbus-mointer
1.dbus-send 可以进行信号的发送
Usage: dbus-send [--help] [--system | --session | --bus=ADDRESS | --peer=ADDRESS]
[--dest=NAME] [--type=TYPE] [--print-reply[=literal]] [--reply-timeout=MSEC] [contents ...]
命令参数说明:
--dest:指定接收消息的连接名称
--print-reply:阻止对已发送消息的答复,打印收到的所有答复。消息类型--type = method_call。
--print-reply=literal:阻止对已发送消息的答复,并打印答复内容,如果答复是对象路径或字符串,则按原样打印,没有标点,转义字符等。
--reply-timeout:等待答复最大毫秒值,默认25秒
--system和--session:系统总线和会话总线,默认会话总线
--bus:在指定的消息总线上注册,通常是dbus-daemon
--peer:发送非DBus消息到指定的DBus服务上,dbus-send将不会调用Hello方法
--sender:发送消息之前,给发送者授权, 退出时,释放该发送者
--type:指定method_call或signal(默认为“ signal”)
案例:
用例形式是:
dbus-send --dest=org.freedesktop.ExampleName \
/org/freedesktop/sample/object/name \
org.freedesktop.ExampleInterface.ExampleMethod \
int32:47 string:'hello world' double:65.32 \
array:string:"1st item","next item","last item" \
dict:string:int32:"one",1,"two",2,"three",3 \
variant:int32:-8 \
objpath:/org/freedesktop/sample/object/name
其中:
–system ##将命令发向系统总线,也可使用–session
–print-reply ## 打印返回结果
–dest=org.freedesktop.ExampleName ##服务名。用户可以用查询命令获得当前系统的所有服务名
/org/freedesktop/sample/object/name ## 对象名。由服务定义
org.bluez.audio.Manager.CreateDevice
org.freedesktop.ExampleInterface.ExampleMethod ##方法名
int32:47 string:‘hello world’ double:65.32
array:string:“1st item”,“next item”,“last item”
dict:string:int32:“one”,1,“two”,2,“three”,3
variant:int32:-8
objpath:/org/freedesktop/sample/object/name ## 参数 类型:值 int32:123
dbus-send的详细用法可以参阅手册($man dbus-send或者$dbus-send --help)。
2. d-feet 查看内核接口
当你准备使用D-Bus实现你的通信功能,D-Feet会很方便:它可以显示service提供的所有对象、信号、和方法。另外还可以通过它实现方法调用。
1. dbus-monitor
使用手册
dbus-monitor 具有两种不同的文本输出模式:“经典”风格的监视模式和配置文件模式
配置文件模式:一种紧凑格式,每条消息只有一行,并且具有微秒分辨率的定时信息
dbus-monitor 也有两种特殊的二进制输出模式:–binary 和–pcap
--binary:二进制模式将输出整个二进制消息流
--pcap:将PCAP文件头添加到输出的开头,并为每个消息添加PCAP消息头
如果未指定任何模式,则 dbus-monitor 将使用监视输出格式。
--system 和 --session表示系统总线和会话总线,默认为--session
--address ADDRESS:监视在ADDRESS处给定的任意消息总线
--profile:使用配置文件模式打印
--monitor:使用dbus-monitor模式打印
输出概要:
type:分为signal和method_call
sender:消息或方法调用者
dest:消息接收或方法拥有者
interface:接口名
path:服务路径
member:方法名或属性名
replay:方法调用的返回值
监视某些系统级接口时,需要加上 sudo 权限,如监视 lastore 更新模块 sudo dbus-monitor --system "interface=com.deepin.lastore.Manager"
监视信号
dbus-monitor type=‘signal’,sender=‘org.gnome.TypingMonitor’,interface=‘org.gnome.TypingMonitor’
监视方法
dbus-monitor --session “interface=com.deepin.daemon.Display”
## 3.D-Bus 需要注意的问题?
todo
[dbus 信号收发小例子](https://blog.csdn.net/wuquan_1230/article/details/87934203?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1.pc_relevant_paycolumn_v3&spm=1001.2101.3001.4242.2&utm_relevant_index=4)
[dbus 官方文档](http://www.freedesktop.org/software/dbus/
)
* [dbus-send](https://blog.csdn.net/machiner1/article/details/44936519/)
* [协议](https://dbus.freedesktop.org/doc/dbus-specification.html#stability)
* [D-Bus体系](http://blog.chinaunix.net/uid-28584979-id-5050928.html)
* [busctl 中文手册](http://www.jinbuguo.com/systemd/busctl.html)
简单实用
* [dbus 应用案例 ****](https://blog.csdn.net/eydwyz/article/details/70175289?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_title~default-1.no_search_link&spm=1001.2101.3001.4242.2)
* [dbus 学习链接 **** 通俗易懂](http://www.fmddlmyy.cn/mytext.html)
*
go dbus 案例
[godbus 学习资料 比较全面](https://pkg.go.dev/github.com/godbus/dbus/v5)
[go dbus 应用](https://www.codeplayer.org/Wiki/go/%E5%9C%A8go%E4%B8%AD%E4%BD%BF%E7%94%A8dbus%E5%92%8Cgsettings.html#org21a125a)