- 浏览: 871525 次
- 性别:
- 来自: 西安
文章分类
最新评论
-
qunhua1861:
我已做好准备,让您无可挑剔。白癜风常识http://www.4 ...
创业路上之谢谢王磊何公道丁凯李亚平黄小润张小兵 -
qunhua1861:
给我一份信任,还您一身健康。白癜风常识http://m.400 ...
创业路上之无尽感谢 -
qunhua1861:
以我真心、关心、耐心,换您放心、安心、舒心。<a hre ...
《博客园精华集》web标准分册第2论筛选结果文章列表 -
saieuler:
真的吗??
物理运动模拟引擎 -
saieuler:
每次都是学会了,过段时间又忘了
记录KMP算法,记录其经典之处。。。
应用程序A和消息总线连接,这个连接获取了一个众所周知的公共名(记作连接A)。应用程序A中有对象A1提供了接口I1,接口I1有方法M1。应用程序B和消息总线连接,要求调用连接A上对象A1的接口I1的方法M1。
在上一讲的加法例子中,上面这段话可以实例化为:应用程序example-service和会话总线连接。这个连接获取了一个众所周知的公共名“org.fmddlmyy.Test”。应用程序example-servic中有对象“/TestObj”提供了接口“org.fmddlmyy.Test.Basic”,接口“org.fmddlmyy.Test.Basic”有方法“Add”。应用程序d-feet和会话总线连接,要求调用连接“org.fmddlmyy.Test”上对象“/TestObj”的接口“org.fmddlmyy.Test.Basic”的方法“Add”。
应用程序B调用应用程序A的方法,其实就是应用程序B向应用程序A发送了一个类型为“method_call”的消息。应用程序A通过一个类型为“method_retutn”的消息将返回值发给应用程序B。我们简单介绍一下D-Bus总线上的消息。
1、D-Bus的消息
上一讲说过最基本的D-Bus协议是一对一的通信协议。与直接使用socket不同,D-Bus是面向消息的协议。 D-Bus的所有功能都是通过在连接上流动的消息完成的。
1.1、消息类型
D-Bus有四种类型的消息:
- method_call 方法调用
- method_return 方法返回
- error 错误
- signal 信号
前面介绍的远程方法调用就用到了method_call和method_return消息。顾名思义,在发生错误时会产生error消息。如果把method_call看作打电话,那么signal消息就是来电了。后面还会详细讨论。
1.2、dbus-send和dbus-monitor
dbus提供了两个小工具:dbus-send和dbus-monitor。我们可以用dbus-send发送消息。用dbus-monitor监视总线上流动的消息。让我们通过dbus-send发送消息来调用前面的Add方法,这时dbus-send充当了应用程序B。用dbus-monitor观察调用过程中的消息。
启动example-service:
$ ./example-service
在另一个控制台启动dbus-monitor:
$ dbus-monitor
dbus-monitor默认监视会话总线。执行:
$ dbus-send --session --type=method_call --print-reply --dest=org.fmddlmyy.Test /TestObj org.fmddlmyy.Test.Basic.Add int32:100 int32:999
输出为:
method return sender=:1.21 -> dest=:1.22 reply_serial=2 int32 1099
dbus-monitor的相关输出包括:
signal sender=org.freedesktop.DBus -> dest=(null destination) path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged string ":1.22" string "" string ":1.22" method call sender=:1.22 -> dest=org.freedesktop.DBus path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=Hello method call sender=:1.22 -> dest=org.fmddlmyy.Test path=/TestObj; interface=org.fmddlmyy.Test.Basic; member=Add int32 100 int32 999 method return sender=:1.21 -> dest=:1.22 reply_serial=2 int32 1099 signal sender=org.freedesktop.DBus -> dest=(null destination) path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged string ":1.22" string ":1.22" string ""
:1.22就是dbus-send在本次调用中与会话总线所建立连接的唯一名。:1.21是连接“org.fmddlmyy.Test”的唯一名。在以上输出中我们可以看到:1.22向“org.fmddlmyy.Test”发送method_call消息,调用Add方法。 :1.21通过method_return消息将调用结果发回:1.22。其它输出信息会在以后说明。
dbus-send的详细用法可以参阅手册。调用远程方法的一般形式是:
$ dbus-send [--system | --session] --type=method_call --print-reply --dest=连接名 对象路径 接口名.方法名 参数类型:参数值 参数类型:参数值
dbus-send支持的参数类型包括:string, int32, uint32, double, byte, boolean。
2、消息总线的方法和信号
2.1、概述
消息总线是一个特殊的应用,它可以在与它连接的应用之间传递消息。可以把消息总线看作一台路由器。正是通过消息总线,D-Bus才在一对一的通信协议基础上实现了多对一和一对多的通信。
消息总线虽然有特殊的转发功能,但消息总线也还是一个应用。其它应用与消息总线的通信也是通过1.1节的基本消息类型完成的。作为一个应用,消息总线也提供了自己的接口,包括方法和信号。
我们可以通过向连接“org.freedesktop.DBus ”上对象“/”发送消息来调用消息总线提供的方法。事实上,应用程序正是通过这些方法连接到消息总线上的其它应用,完成请求公共名等工作的。
2.2、清单
消息总线对象支持第一讲中提到的标准接口"org.freedesktop.DBus.Introspectable",我们可以调用org.freedesktop.DBus.Introspectable.Introspect方法查看消息总线对象支持的接口。例如:
$ dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.Introspectable.Introspect
输出为:
method return sender=org.freedesktop.DBus -> dest=:1.20 reply_serial=2 string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node> <interface name="org.freedesktop.DBus.Introspectable"> <method name="Introspect"> <arg name="data" direction="out" type="s"/> </method> </interface> <interface name="org.freedesktop.DBus"> <method name="Hello"> <arg direction="out" type="s"/> </method> <method name="RequestName"> <arg direction="in" type="s"/> <arg direction="in" type="u"/> <arg direction="out" type="u"/> </method> <method name="ReleaseName"> <arg direction="in" type="s"/> <arg direction="out" type="u"/> </method> <method name="StartServiceByName"> <arg direction="in" type="s"/> <arg direction="in" type="u"/> <arg direction="out" type="u"/> </method> <method name="NameHasOwner"> <arg direction="in" type="s"/> <arg direction="out" type="b"/> </method> <method name="ListNames"> <arg direction="out" type="as"/> </method> <method name="ListActivatableNames"> <arg direction="out" type="as"/> </method> <method name="AddMatch"> <arg direction="in" type="s"/> </method> <method name="RemoveMatch"> <arg direction="in" type="s"/> </method> <method name="GetNameOwner"> <arg direction="in" type="s"/> <arg direction="out" type="s"/> </method> <method name="ListQueuedOwners"> <arg direction="in" type="s"/> <arg direction="out" type="as"/> </method> <method name="GetConnectionUnixUser"> <arg direction="in" type="s"/> <arg direction="out" type="u"/> </method> <method name="GetConnectionUnixProcessID"> <arg direction="in" type="s"/> <arg direction="out" type="u"/> </method> <method name="GetConnectionSELinuxSecurityContext"> <arg direction="in" type="s"/> <arg direction="out" type="ay"/> </method> <method name="ReloadConfig"> </method> <method name="GetId"> <arg direction="out" type="s"/> </method> <signal name="NameOwnerChanged"> <arg type="s"/> <arg type="s"/> <arg type="s"/> </signal> <signal name="NameLost"> <arg type="s"/> </signal> <signal name="NameAcquired"> <arg type="s"/> </signal> </interface> </node> "
从输出可以看到会话总线对象支持标准接口“org.freedesktop.DBus.Introspectable”和接口“org.freedesktop.DBus”。接口“org.freedesktop.DBus”有16个方法和3个信号。下表列出了“org.freedesktop.DBus”的12个方法的简要说明:
org.freedesktop.DBus.RequestName (in STRING name, in UINT32 flags, out UINT32 reply) | 请求公众名。其中flag定义如下: DBUS_NAME_FLAG_ALLOW_REPLACEMENT 1 DBUS_NAME_FLAG_REPLACE_EXISTING 2 DBUS_NAME_FLAG_DO_NOT_QUEUE 4 返回值reply定义如下: DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2 DBUS_REQUEST_NAME_REPLY_EXISTS 3 DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4 |
org.freedesktop.DBus.ReleaseName (in STRING name, out UINT32 reply) | 释放公众名。返回值reply定义如下: DBUS_RELEASE_NAME_REPLY_RELEASED 1 DBUS_RELEASE_NAME_REPLY_NON_EXISTENT 2 DBUS_RELEASE_NAME_REPLY_NOT_OWNER 3 |
org.freedesktop.DBus.Hello (out STRING unique_name) | 一个应用在通过消息总线向其它应用发消息前必须先调用Hello获取自己这个连接的唯一名。返回值就是连接的唯一名。dbus没有定义专门的切断连接命令,关闭socket就是切断连接。 在1.2节的dbus-monitor输出中可以看到dbus-send调用消息总线的Hello方法。 |
org.freedesktop.DBus.ListNames (out ARRAY of STRING bus_names) | 返回消息总线上已连接的所有连接名,包括所有公共名和唯一名。例如连接“org.fmddlmyy.Test”同时有公共名“org.fmddlmyy.Test”和唯一名“:1.21”,这两个名称都会被返回。 |
org.freedesktop.DBus.ListActivatableNames (out ARRAY of STRING bus_names) | 返回所有可以启动的服务名。dbus支持按需启动服务,即根据应用程序的请求启动服务。 |
org.freedesktop.DBus.NameHasOwner (in STRING name, out BOOLEAN has_owner) | 检查是否有连接拥有指定名称。 |
org.freedesktop.DBus.StartServiceByName (in STRING name, in UINT32 flags, out UINT32 ret_val) | 按名称启动服务。参数flags暂未使用。返回值ret_val定义如下: 1 服务被成功启动 2 已经有连接拥有要启动的服务名 |
org.freedesktop.DBus.GetNameOwner (in STRING name, out STRING unique_connection_name) | 返回拥有指定公众名的连接的唯一名。 |
org.freedesktop.DBus.GetConnectionUnixUser (in STRING connection_name, out UINT32 unix_user_id) | 返回指定连接对应的服务器进程的Unix用户id。 |
org.freedesktop.DBus.AddMatch (in STRING rule) | 为当前连接增加匹配规则。 |
org.freedesktop.DBus.RemoveMatch (in STRING rule) | 为当前连接去掉指定匹配规则。 |
org.freedesktop.DBus.GetId (out STRING id) | 返回消息总线的ID。这个ID在消息总线的生命期内是唯一的。 |
接口“org.freedesktop.DBus”的3个信号是:
org.freedesktop.DBus.NameOwnerChanged (STRING name, STRING old_owner, STRING new_owner) | 指定名称的拥有者发生了变化。 |
org.freedesktop.DBus.NameLost (STRING name) | 通知应用失去了指定名称的拥有权。 |
org.freedesktop.DBus.NameAcquired (STRING name) | 通知应用获得了指定名称的拥有权。 |
2.3、练习
让我们来试试消息总线提供的方法。
2.3.1、从ListName到d-feet的基本逻辑
用dbus-send调用:
$ dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
输出为:
method return sender=org.freedesktop.DBus -> dest=:1.23 reply_serial=2 array [ string "org.freedesktop.DBus" string "org.freedesktop.Notifications" string "org.freedesktop.Tracker" string "org.freedesktop.PowerManagement" string ":1.7" string ":1.8" string "org.gnome.ScreenSaver" string ":1.9" string ":1.10" string ":1.22" string ":1.11" string "org.gnome.GnomeVFS.Daemon" string ":1.23" string ":1.12" string ":1.13" string ":1.0" string ":1.14" string ":1.1" string ":1.15" string ":1.2" string ":1.16" string ":1.3" string "org.gnome.GkbdConfigRegistry" string ":1.4" string "org.fmddlmyy.Test" string ":1.5" string "org.gnome.SettingsDaemon" string ":1.6" ]
这是会话总线当前已连接的连接名。在d-feet窗口的左侧窗口显示的就是ListNames返回的连接名。聪明的读者也许已经想到使用消息总线的“org.freedesktop.DBus.ListNames”方法和各连接的“org.freedesktop.DBus.Introspectable.Introspect”,我们就可以像d-feet一样查看总线上所有连接的所有对象的所有接口的所有方法和信号。
你的想法很好。但有一个问题,我们必须对连接中的对象调用“org.freedesktop.DBus.Introspectable.Introspect”方法。 ListNames只列出了连接名,我们怎么获取连接中的对象路径呢?
答案很简单,如果我们不知道对象路径就从根目录开始吧。连接中的对象是按照树型结构组织的。我们遍历连接的对象树就可以找到所有的对象。调用对象的“org.freedesktop.DBus.Introspectable.Introspect”方法就可以查看对象的所有接口的所有方法和信号。例如:假设我们不知道连接"org.fmddlmyy.Test"里有什么对象,我们可以对根对象"/"执行:
$ dbus-send --session --type=method_call --print-reply --dest=org.fmddlmyy.Test / org.freedesktop.DBus.Introspectable.Introspect
输出为:
method return sender=:1.22 -> dest=:1.25 reply_serial=2 string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node> <node name="TestObj"/> </node> "
"org.fmddlmyy.Test"的对象树的根节点只有一个子节点"TestObj",再查看"/TestObj":
$ dbus-send --session --type=method_call --print-reply --dest=org.fmddlmyy.Test /TestObj org.freedesktop.DBus.Introspectable.Introspect
输出为:
method return sender=:1.22 -> dest=:1.26 reply_serial=2 string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node> <interface name="org.freedesktop.DBus.Introspectable"> <method name="Introspect"> <arg name="data" direction="out" type="s"/> </method> </interface> <interface name="org.freedesktop.DBus.Properties"> <method name="Get"> <arg name="interface" direction="in" type="s"/> <arg name="propname" direction="in" type="s"/> <arg name="value" direction="out" type="v"/> </method> <method name="Set"> <arg name="interface" direction="in" type="s"/> <arg name="propname" direction="in" type="s"/> <arg name="value" direction="in" type="v"/> </method> <method name="GetAll"> <arg name="interface" direction="in" type="s"/> <arg name="props" direction="out" type="a{sv}"/> </method> </interface> <interface name="org.fmddlmyy.Test.Basic"> <method name="Add"> <arg name="arg0" type="i" direction="in"/> <arg name="arg1" type="i" direction="in"/> <arg name="ret" type="i" direction="out"/> </method> </interface> </node> "
作为一个练习,让我们来查看系统总线的上的bluez接口。执行:
$ dbus-send --system --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
输出为:
method return sender=org.freedesktop.DBus -> dest=:1.30 reply_serial=2 array [ string "org.freedesktop.DBus" string ":1.7" string ":1.8" string ":1.9" string "org.freedesktop.SystemToolsBackends" string ":1.30" string "org.freedesktop.NetworkManagerInfo" string ":1.20" string "org.freedesktop.Avahi" string ":1.21" string "org.bluez" string ":1.22" string "org.freedesktop.NetworkManager" string "org.freedesktop.ConsoleKit" string ":1.23" string "com.redhat.dhcp" string ":1.13" string ":1.0" string ":1.14" string ":1.1" string ":1.15" string ":1.2" string "org.freedesktop.Hal" string "com.redhat.NewPrinterNotification" string ":1.16" string ":1.3" string ":1.17" string ":1.4" string ":1.18" string ":1.5" string ":1.19" string ":1.6" ]
我们看到连接"org.bluez"。查看它的根对象:
$ dbus-send --system --type=method_call --print-reply --dest=org.bluez / org.freedesktop.DBus.Introspectable.Introspect
输出为:
method return sender=:1.7 -> dest=:1.31 reply_serial=2 string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node> <node name="org"/> </node> "
接着查对象"/org":
$ dbus-send --system --type=method_call --print-reply --dest=org.bluez /org org.freedesktop.DBus.Introspectable.Introspect
输出为:
method return sender=:1.7 -> dest=:1.32 reply_serial=2 string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node> <node name="bluez"/> </node> "
接着查对象"/org/bluez":
$ dbus-send --system --type=method_call --print-reply --dest=org.bluez /org/bluez org.freedesktop.DBus.Introspectable.Introspect
输出为:
method return sender=:1.7 -> dest=:1.33 reply_serial=2 string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node name="/org/bluez"> <interface name="org.bluez.Manager"> <method name="InterfaceVersion"> <arg type="u" direction="out"/> </method> <method name="DefaultAdapter"> <arg type="s" direction="out"/> </method> <method name="FindAdapter"> <arg type="s" direction="in"/> <arg type="s" direction="out"/> </method> <method name="ListAdapters"> <arg type="as" direction="out"/> </method> <method name="FindService"> <arg type="s" direction="in"/> <arg type="s" direction="out"/> </method> <method name="ListServices"> <arg type="as" direction="out"/> </method> <method name="ActivateService"> <arg type="s" direction="in"/> <arg type="s" direction="out"/> </method> <signal name="AdapterAdded"> <arg type="s"/> </signal> <signal name="AdapterRemoved"> <arg type="s"/> </signal> <signal name="DefaultAdapterChanged"> <arg type="s"/> </signal> <signal name="ServiceAdded"> <arg type="s"/> </signal> <signal name="ServiceRemoved"> <arg type="s"/> </signal> </interface> <interface name="org.bluez.Database"> <method name="AddServiceRecord"> <arg type="ay" direction="in"/> <arg type="u" direction="out"/> </method> <method name="AddServiceRecordFromXML"> <arg type="s" direction="in"/> <arg type="u" direction="out"/> </method> <method name="UpdateServiceRecord"> <arg type="u" direction="in"/> <arg type="ay" direction="in"/> </method> <method name="UpdateServiceRecordFromXML"> <arg type="u" direction="in"/> <arg type="s" direction="in"/> </method> <method name="RemoveServiceRecord"> <arg type="u" direction="in"/> </method> <method name="RegisterService"> <arg type="s" direction="in"/> <arg type="s" direction="in"/> <arg type="s" direction="in"/> </method> <method name="UnregisterService"> <arg type="s" direction="in"/> </method> <method name="RequestAuthorization"> <arg type="s" direction="in"/> <arg type="s" direction="in"/> </method> <method name="CancelAuthorizationRequest"> <arg type="s" direction="in"/> <arg type="s" direction="in"/> </method> </interface> <interface name="org.bluez.Security"> <method name="RegisterDefaultPasskeyAgent"> <arg type="s" direction="in"/> </method> <method name="UnregisterDefaultPasskeyAgent"> <arg type="s" direction="in"/> </method> <method name="RegisterPasskeyAgent"> <arg type="s" direction="in"/> <arg type="s" direction="in"/> </method> <method name="UnregisterPasskeyAgent"> <arg type="s" direction="in"/> <arg type="s" direction="in"/> </method> <method name="RegisterDefaultAuthorizationAgent"> <arg type="s" direction="in"/> </method> <method name="UnregisterDefaultAuthorizationAgent"> <arg type="s" direction="in"/> </method> </interface> <node name="service_audio"/> <node name="service_input"/> <node name="service_network"/> <node name="service_serial"/> </node> "
我们看到了对象"/org/bluez"的所有接口。对象"/org/bluez"还有子节点"service_audio"、"service_input"、"service_network"和"service_serial"。必要时我们可以接着查下去。d-feet的基本逻辑就是这样。后面我们会自己实现一个dteeth。dteeth是命令行程序,可以遍历指定连接的对象树,列出所有对象的所有接口的方法和信号。
相关推荐
注:该文档不是我原创的,摘自http://blog.csdn.net/fmddlmyy,我只是把相关文档整合在一起,希望有需要的朋友看起来能够方便一些。
D-BUS实例讲解,结合例子,讲解透彻啊
dbus - 原生Go绑定 D-Bus 消息总线系统
dbus是Unix系统下标准支持的数据访问总线
基于dbus-glib注册总线接口实例,包含服务端与客户端,以及规则文件和提权文件.其中缺少的依赖库需要自己安装
离线安装包,亲测可用
linux下的总线通讯DBus的一个实例,还不错。
dbus异步 一个纯Rust编写的异步DBus库。 用法 将此添加到您的Cargo.toml : [ dependencies ] dbus-async = " ~2.1.0 " 您必须指定应使用哪个Tokio Runtime。 对于多线程,请将其添加到您的Cargo.toml : ...
本示例用QT实现,分别演示了通过QDBusMessage、QDBusInterface及代理的方式进行dbus调用的方法。 其中: numoperator类中实现了...可同时运行多个实例程序,在不同的实例上操作后,其它实例上取得的数据也会是一致的。
在0.9中, dbus::tree模块移至dbus-tree板条箱(但请考虑迁移至dbus-crossroads )。 如果您当前正在使用0.6.x的dbus并想升级到更高版本,则可以阅读。 额外的板条箱 roadroads简化了方法分发服务器的构建。 将D...
python-dbus-next是DBus的Python库,旨在成为功能齐全的高级库,主要用于将应用程序集成到Linux桌面和移动环境中。 桌面应用程序开发人员可以通过实现常见的DBus标准接口或创建自定义插件接口,使用此库将其应用...
centos7 可使用的 dbus rpm包 包含 dbus 与 dbus-libs 两个包,一个是长期支持版 1.12 一个是 ...注意的第二点:卸载系统自带dbus时报错可以忽略,没有关系的,只要新安装的启动没问题即可,日志在 /var/log/message
升压 D-Bus 这是一个由 Boost.Asio 提供支持的简单 D-Bus 绑定。 我尽可能地遵循 Asio 的习惯用法。 代码示例 # include # include # include < dbus> using namespace std ;... dbus::endpoint
Dbus数据总线平台安装文档
这些方案都不能算完美,我们在了解和考虑了不同实现方式后,认为要想同时解决数据一致性和实时性,比较合理的方法应该是基于日志的解决方案,同时能够提供消息订阅的方式给下游系统使用。 DBus(数据总线)项目就是...
官方离线安装包,亲测可用
复制配置文件以允许服务在系统总线上运行 # cp org.fubar.signal1.conf /etc/dbus-1/system.d/ 编译C版本 # ./build.sh 运行测试服务 # ./spamsignals server 运行测试客户端 # ./spamsignals client 运行测试...
里面有两个doc文档,分别介绍Dbus的作用以及例程说明。
my $dbus = Protcol::DBus::Client::system(); # Authentication and “Hello” call/response: $dbus->initialize(); $dbus->send_call( path => '/org/freedesktop/DBus', interface => 'org....
离线安装包,亲测可用