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 "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">

  ">
    ">
      " type="s"/>
    
    ">
      in" type="s"/>
      in" type="u"/>
      " type="u"/>
    
    ">
      in" type="s"/>
      " type="u"/>
    
    ">
      in" type="s"/>
      in" type="u"/>
      " type="u"/>
    
    ">
      in" type="a{ss}"/>
    
    ">
      in" type="s"/>
      " type="b"/>
    
    ">
      " type="as"/>
    
    ">
      " type="as"/>
    
    ">
      in" type="s"/>
    
    ">
      in" type="s"/>
    
    ">
      in" type="s"/>
      " type="s"/>
    
    ">
      in" type="s"/>
      " type="as"/>
    
    ">
      in" type="s"/>
      " type="u"/>
    
    ">
      in" type="s"/>
      " type="u"/>
    
    ">
      in" type="s"/>
      " type="ay"/>
    
    ">
      in" type="s"/>
      " type="ay"/>
    
    ">
    
    ">
      " type="s"/>
    
    ">
      in" type="s"/>
      " type="a{sv}"/>
    
    " type="as" access="read">
      " value="const"/>
    
    " type="as" access="read">
      " value="const"/>
    
    ">
      "/>
      "/>
      "/>
    
    ">
      "/>
    
    ">
      "/>
    
  
  ">
    ">
      " type="s"/>
    
  
  ">
    ">
      " type="s"/>
    
    ">
    
  
  "/>

"

从输出可以看到会话总线对象支持标准接口“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 "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">

 ">
  "/>
  ">
   " name="machine_uuid" direction="out"/>
  
 
 ">
  ">
   " type="s" direction="out"/>
  
 
 ">
  ">
   " direction="in" type="s"/>
   " direction="in" type="s"/>
   " direction="out" type="v"/>
  
  ">
   " direction="in" type="s"/>
   " direction="out" type="a{sv}"/>
  
  ">
   " direction="in" type="s"/>
   " direction="in" type="s"/>
   " direction="in" type="v"/>
  
  ">
   " name="interface"/>
   {sv}" name="changed_properties"/>
   " name="invalidated_properties"/>
  
 
 ">
  ">
   {oa{sa{sv}}}" name="object_paths_interfaces_and_properties" direction="out"/>
  
  ">
   " name="object_path"/>
   {sa{sv}}" name="interfaces_and_properties"/>
  
  ">
   " name="object_path"/>
   " name="interfaces"/>
  
 
 "/>

"

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

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 "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">

 ">
  "/>
  ">
   " name="machine_uuid" direction="out"/>
  
 
 ">
  ">
   " type="s" direction="out"/>
  
 
 ">
  ">
   " direction="in" type="s"/>
   " direction="in" type="s"/>
   " direction="out" type="v"/>
  
  ">
   " direction="in" type="s"/>
   " direction="out" type="a{sv}"/>
  
  ">
   " direction="in" type="s"/>
   " direction="in" type="s"/>
   " direction="in" type="v"/>
  
  ">
   " name="interface"/>
   {sv}" name="changed_properties"/>
   " name="invalidated_properties"/>
  
 
 "/>

"
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协议信息:

  • D-Bus规格
  • txdbus文档中的D总线概述
  • Jeroen Vermeulen的基础知识简介
  • Qt文档中的D-Bus简介
  • 常问问题
  • 概述图片PNG SVG
  • D-Bus教程(不完整,包含一些绑定和重新实现的内容)
  • 配置文件DTD
  • 如果您对DBus中的某些概念感到困惑,请看一些类比
  • 一些用于D-Bus的工具。请注意,D-Bus规范不完整,尤其是在其对消息总线守护程序的描述中。该协议本身的规范相当完整,尽管并不总是清晰或精确的。欢迎您的补丁!同时,您可能需要阅读参考实现源代码来补充对规范的阅读。

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

  • API参考手册,用于参考实现(libdbus)
  • 参考实施手册和高级TODO中的@todo项目
  • 浏览参考实现源
  • dbus-daemon(1)(包括配置文件docs)
  • dbus发送(1) dbus监控(1) dbus启动(1) dbus-uuidgen(1)
  • HACKING 作者
  • 新闻 ChangeLog 自述文件
  • 测试计划
  • Tarball包含以上大多数文档。请记住,libdbus是一个低级库,旨在用作语言绑定的后端,并具有实现dbus-daemon所需的额外复杂性。如果使用更高级别的包装程序或重新实现,将为您省去很多麻烦。这些文档通常从绑定页面链接。

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

  • Ross Burton的“使用D-BUS连接桌面应用程序”(IBM developerWorks)(2004年7月)
  • John Palmieri的“ Get on D-BUS”(红帽杂志)(2005年1月)
  • 罗伯特·洛夫(Robert Love )的“ Get on the D-BUS”(Linux期刊)(2005年1月)
  • RaphaÃlSlinckx撰写的“ DBus缺少的教程-DBus激活”(2005年)
  • 马修·约翰逊(Matthew Johnson)的D-Bus低级API教程(2005年11月)
  • Aaron Seigo和KDE社区的D-BUS简介(2007)
  • Rony G. Flatscher撰写的“ ooRexx的D-Bus语言绑定简介”(2011年12月,D-Bus概念简介和ooRexx绑定简介)

你可能感兴趣的:(ARM,bmc)