dbus(二)-- 消息和消息总线

消息和消息总线

应用程序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观察调用过程中的消息。

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、清单

在FCP和AC的板子上使用dbus-send,需要先执行export $(dbus-launch).

root@xxxx-obmc:~# dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
Failed to open connection to "session" message bus: Using X11 for dbus-daemon autolaunch was disabled at compile time, set your DBUS_SESSION_BUS_ADDRESS instead
root@xxxx-obmc:~# export $(dbus-launch)
root@xxxx-obmc:~#
root@xxxx-obmc:~# dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
method return time=61305.454012 sender=org.freedesktop.DBus -> destination=:1.0 serial=3 reply_serial=2
   array [
      string "org.freedesktop.DBus"
      string ":1.0"
   ]
root@xxxx-obmc:~#

消息总线对象支持第一讲中提到的标准接口"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
root@xxxx-obmc:~# dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.Introspectable.Introspect
method return time=109.212525 sender=org.freedesktop.DBus -> destination=:1.1 serial=3 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">
    <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="UpdateActivationEnvironment">
      <arg direction="in" type="a{ss}"/>
    </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="GetAdtAuditSessionData">
      <arg direction="in" type="s"/>
      <arg direction="out" type="ay"/>
    </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>
    <method name="GetConnectionCredentials">
      <arg direction="in" type="s"/>
      <arg direction="out" type="a{sv}"/>
    </method>
    <property name="Features" type="as" access="read">
      <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
    </property>
    <property name="Interfaces" type="as" access="read">
      <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
    </property>
    <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>
  <interface name="org.freedesktop.DBus.Introspectable">
    <method name="Introspect">
      <arg direction="out" type="s"/>
    </method>
  </interface>
  <interface name="org.freedesktop.DBus.Peer">
    <method name="GetMachineId">
      <arg direction="out" type="s"/>
    </method>
    <method name="Ping">
    </method>
  </interface>
  <node name="org/freedesktop/DBus"/>
</node>
"

从输出可以看到会话总线对象支持标准接口“org.freedesktop.DBus.Introspectable”和接口“org.freedesktop.DBus”。 接口“org.freedesktop.DBus”有16个方法和3个信号。下表列出了“org.freedesktop.DBus”的12个方法的简要说明

mathod说明
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)通知应用获得了指定名称的拥有权。

参数session和system的区别:

dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
method return time=875.939015 sender=org.freedesktop.DBus -> destination=:1.2 serial=3 reply_serial=2
   array [
      string "org.freedesktop.DBus"
      string ":1.2"
   ]
root@obmc:~#
root@obmc:~#
root@obmc:~#
root@obmc:~# dbus-send --system --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
method return time=908.657105 sender=org.freedesktop.DBus -> destination=:1.143 serial=4294967295 reply_serial=2
   array [
      string "org.freedesktop.DBus"
  ......
   ]

xyz.openbmc_project.Control.Host.NMI为例子,查看他的根对象。

root@obmc:~# dbus-send --system --type=method_call --print-reply --dest=xyz.openbmc_project.Control.Host.NMI / org.freedesktop.DBus.Introspectable.Introspect
method return time=1482.867385 sender=:1.50 -> destination=:1.144 serial=150 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.Peer">
  <method name="Ping"/>
  <method name="GetMachineId">
   <arg type="s" name="machine_uuid" direction="out"/>
  </method>
 </interface>
 <interface name="org.freedesktop.DBus.Introspectable">
  <method name="Introspect">
   <arg name="data" type="s" direction="out"/>
  </method>
 </interface>
 <interface name="org.freedesktop.DBus.Properties">
  <method name="Get">
   <arg name="interface" direction="in" type="s"/>
   <arg name="property" direction="in" type="s"/>
   <arg name="value" direction="out" type="v"/>
  </method>
  <method name="GetAll">
   <arg name="interface" direction="in" type="s"/>
   <arg name="properties" direction="out" type="a{sv}"/>
  </method>
  <method name="Set">
   <arg name="interface" direction="in" type="s"/>
   <arg name="property" direction="in" type="s"/>
   <arg name="value" direction="in" type="v"/>
  </method>
  <signal name="PropertiesChanged">
   <arg type="s" name="interface"/>
   <arg type="a{sv}" name="changed_properties"/>
   <arg type="as" name="invalidated_properties"/>
  </signal>
 </interface>
 <interface name="org.freedesktop.DBus.ObjectManager">
  <method name="GetManagedObjects">
   <arg type="a{oa{sa{sv}}}" name="object_paths_interfaces_and_properties" direction="out"/>
  </method>
  <signal name="InterfacesAdded">
   <arg type="o" name="object_path"/>
   <arg type="a{sa{sv}}" name="interfaces_and_properties"/>
  </signal>
  <signal name="InterfacesRemoved">
   <arg type="o" name="object_path"/>
   <arg type="as" name="interfaces"/>
  </signal>
 </interface>
 <node name="xyz"/>
</node>
"

如上,他的根目录下有一个子节点,查找信息如下,获取到的接口信息与在根目录下获取的信息一致。

root@obmc:~# dbus-send --system --type=method_call --print-reply --dest=xyz.openbmc_project.Control.Host.NMI /xyz org.freedesktop.DBus.Introspectable.Introspect
method return time=1762.447872 sender=:1.50 -> destination=:1.145 serial=151 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.Peer">
  <method name="Ping"/>
  <method name="GetMachineId">
   <arg type="s" name="machine_uuid" direction="out"/>
  </method>
 </interface>
 <interface name="org.freedesktop.DBus.Introspectable">
  <method name="Introspect">
   <arg name="data" type="s" direction="out"/>
  </method>
 </interface>
 <interface name="org.freedesktop.DBus.Properties">
  <method name="Get">
   <arg name="interface" direction="in" type="s"/>
   <arg name="property" direction="in" type="s"/>
   <arg name="value" direction="out" type="v"/>
  </method>
  <method name="GetAll">
   <arg name="interface" direction="in" type="s"/>
   <arg name="properties" direction="out" type="a{sv}"/>
  </method>
  <method name="Set">
   <arg name="interface" direction="in" type="s"/>
   <arg name="property" direction="in" type="s"/>
   <arg name="value" direction="in" type="v"/>
  </method>
  <signal name="PropertiesChanged">
   <arg type="s" name="interface"/>
   <arg type="a{sv}" name="changed_properties"/>
   <arg type="as" name="invalidated_properties"/>
  </signal>
 </interface>
 <node name="openbmc_project"/>
</node>
"
2.3.2、ListActivatableNames和服务器的自动启动

这里使用session和system获得的结果不一致。

root@obmc:~# dbus-send --system --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListActivatableNames
method return time=1939.107887 sender=org.freedesktop.DBus -> destination=:1.146 serial=4294967295 reply_serial=2
   array [
      string "org.freedesktop.DBus"
      string "org.freedesktop.Avahi"
      string "org.freedesktop.hostname1"
      string "org.freedesktop.login1"
      string "org.freedesktop.network1"
      string "org.freedesktop.resolve1"
      string "org.freedesktop.systemd1"
      string "org.freedesktop.timedate1"
      string "org.freedesktop.timesync1"
      string "xyz.openbmc_project.EntityManager"
   ]
root@obmc:~# dbus-send --session --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListActivatableNames
method return time=1960.060127 sender=org.freedesktop.DBus -> destination=:1.3 serial=3 reply_serial=2
   array [
      string "org.freedesktop.DBus"
      string "org.freedesktop.systemd1"
   ]

执行:

root@obmc:~# cat /usr/share/dbus-1/services/*|grep Name|awk -F= '{print $2}'|sort
org.freedesktop.systemd1

它将"/usr/share/dbus-1/services/“下所有文件交给grep筛选出包含“Name”的行。将包含“Name”的行交给awk处理,awk用”="作为列分隔符,取出第二列然后交给sort排序后输出。 "/usr/share/dbus-1/services/"目录就是dbus放service文件的地方。需要自动启动的服务器会在这个目录放一个service文件,例如:

root@obmc:~# cat /usr/share/dbus-1/services/org.freedesktop.systemd1.service
#  SPDX-License-Identifier: LGPL-2.1+
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.
[D-BUS Service]
Name=org.freedesktop.systemd1
Exec=/bin/false
User=root

Name是服务器的公共名,Exec是服务器的执行路径。在客户请求一个服务,但该服务还没有启动时。dbus会根据service文件自动启动服务。

文献资料

doc /子目录中的一些内容是预先构建的,可以在此处浏览。如果您是D-Bus的新手,则该教程可能是最好的入门指南(即使它非常不完整,也涵盖了基础知识)。

通用D-Bus协议信息:

特定于参考实现dbus的文档:

网络上的文章,包括一些教程:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值