linux 进程间通信 dbus-glib【实例】详解一(附代码)(d-feet工具使用)

linux 进程间通信 dbus-glib【实例】详解二(上) 消息和消息总线(附代码)

linux 进程间通信 dbus-glib【实例】详解二(下) 消息和消息总线(ListActivatableNames和服务器的自动启动)(附代码)

linux 进程间通信 dbus-glib【实例】详解三 数据类型和dteeth(类型签名type域)(层级结构:服务Service --> Node(对象、object) 等 )(附代码)

linux 进程间通信 dbus-glib【实例】详解四(上) C库 dbus-glib 使用(附代码)(编写接口描述文件.xml,dbus-binding-tool工具生成绑定文件)

注意层级:服务Service --> Node(对象、object) --> 接口Interface --> 方法Method & 信号Signal

文章目录

  • 1、dbus的数据类型
  • 2、dteeth
    • 2.1、运行dteeth
    • 2.2、源代码
    • 2.3、dteeth的主要逻辑
    • 2.3、_introspect_parser的输出格式
  • 3、python基础
    • 3.1、代码块和缩进
    • 3.2、脚本文件格式
    • 3.3、列表、元组和字典
    • 4、结束语

我想在freerunner(一个开源linux手机)上查看fso(openmoko的诸多软件版本之一)的dbus信息。但fso的python没有gtk模块,跑不了d-feet。 在上一讲我介绍了d-feet的基本思路:用“org.freedesktop.DBus.ListNames”枚举消息总线上的连接,用“org.freedesktop.DBus.Introspectable.Introspect” 从"/"开始遍历连接的对象树。上一讲我们手工查看了两个连接,那么我们能不能写一个程序自动遍历连接的对象树, 输出指定连接的所有对象的所有接口的所有方法和信号?

当然可以,为此我写了一个叫dteeth的python脚本。不过在介绍这个脚本前,让我们先看看dbus的数据类型。

1、dbus的数据类型

dbus用xml描述接口,例如:

<?xml version="1.0" encoding="UTF-8" ?><node name="/org/freesmartphone/GSM/Device"><interface name="org.freesmartphone.GSM.SMS"><method name="SendMessage"><arg name="number" type="s"/><arg name="contents" type="s"/><arg name="featuremap" type="a{sv}"/><arg type="i" direction="out"/></method><signal name="IncomingMessage"><arg name="address" type="s"/><arg name="contents" type="s"/><arg name="features" type="a{sv}"/></signal></interface>
</node>

其实前两讲已经看过很多例子了。node就是接口中的对象

node可以包含node,构成对象树。 dbus的接口描述文件统一采用utf-8编码。 我相信读者很容易理解这个接口描述文件。我只想解释一下描述参数数据类型的type域。 dbus的数据类型是由"s"或"a{sv}"这样的类型签名(Type Signatures)定义的。 类型签名中可以使用以下标记:


a表示数组,数组元素的类型由a后面的标记决定。例如:

  • "as"是字符串数组。
  • 数组"a(i(ii))"的元素是一个结构。用括号将成员的类型括起来就表示结构了,结构可以嵌套。
  • 数组"a{sv}“的元素是一个键-值对。”{sv}"表示键类型是字符串,值类型是VARIANT。

在以后的例子中,我们会亲手实现上面这个xml描述的接口,包括服务器和客户程序。 到时候,读者会对dbus的数据类型有更直观的认识。

2、dteeth

2.1、运行dteeth

可以从这里下载dteeth的源代码。其中包含两个python脚本:dteeth.py和_introspect_parser.py。 dteeth.py是我写的。_introspect_parser.py是个开源模块,可以分析Introspect返回的xml数据。

dteeth用法如下:

$ ./dteeth.py -h
Usage: dteeth [--system] <name of a connection on the bus >

默认连接session总线,除非你加上–system。可以一次指定同一消息总线的多个连接。先在PC上试一试:

$ ./dteeth.py org.fmddlmyy.Test
org.fmddlmyy.Test/TestObjorg.fmddlmyy.Test.BasicmethodsAdd( in i arg0 , in i arg1 , out i ret )org.freedesktop.DBus.IntrospectablemethodsIntrospect( out s data )org.freedesktop.DBus.PropertiesmethodsSet( in s interface , in s propname , in v value )GetAll( in s interface , out a{sv} props )Get( in s interface , in s propname , out v value )

我也在fso版本的freerunner手机上运行了一下,得到了org.freesmartphone.ogsmd的所有对象的所有的接口的所有方法和信号:(打印出来太多了,略)

2.2、源代码

下面是dteeth的源代码:

$ cat -n dteeth.py1  #!/usr/bin/env python2  # -*- coding: utf-8 -*-34  import dbus5  import _introspect_parser6  import getopt, sys78  MARGIN_WIDTH = 49  ONE_MARGIN = ' ' * MARGIN_WIDTH1011  # signal是个元组,它有一个元素,是一个列表。列表的元素是signal的参数12  # 列表的每个元素都是字典。它有两个元素,键值分别是'type'和'name'13  def show_signal(name, signal, margin):14      print margin+name+'(',15      args = signal[0]16      for i, arg in enumerate(args):17          if i > 0:18              print ',',19          if arg['name']:20              print '%s %s' % (arg['type'], arg['name']),21          else:22              print '%s' % arg['type'],23      print  ')'2425  # method是个元组,它有两个元素,都是列表。前一个列表的元素是输入参数,后一个列表的元素是输出参数26  def show_method(name, method, margin):27      print margin+name+'(',28  # 输入参数29      args = method[0]30      in_num = len(args)31      out_num = len(method[1])32      for i, arg in enumerate(args):33          if i > 0:34              print ',',35          if arg['name']:36              print 'in %s %s' % (arg['type'], arg['name']),37          else:38              print 'in %s' % arg['type'],39  # 输出参数40      if (in_num > 0) and (out_num > 0) :41          print ',',42      args = method[1]43      for i, arg in enumerate(args):44          if i > 0:45              print ',',46          if arg['name']:47              print 'out %s %s' % (arg['type'], arg['name']),48          else:49              print 'out %s' % arg['type'],50      print  ')'5152  def show_property(name, property, margin):53      print margin+name54      print margin,55      print property5657  # interfaces是个字典,它有三个元素,键值分别是'signals'、'methods'和'properties'58  def show_iface(name, iface, margin):59      print margin + name60      margin += ONE_MARGIN61      signals=iface['signals']62      l = len(signals)63      if l > 0:64          print margin+'signals'65          for node in signals:66              show_signal(node, signals[node], margin+ONE_MARGIN)6768      methods=iface['methods']69      l = len(methods)70      if l > 0:71          print margin+'methods'72          for node in methods:73              show_method(node, methods[node], margin+ONE_MARGIN)7475      properties=iface['properties']76      l = len(properties)77      if l > 0:78          print margin+'properties'79          for node in properties:80              show_property(node, properties[node], margin+ONE_MARGIN)8182  def show_obj(bus, name, obj_name, margin):83      obj=bus.get_object(name, obj_name)84      iface=dbus.Interface(obj, 'org.freedesktop.DBus.Introspectable')85      xml=iface.Introspect();86      data = _introspect_parser.process_introspection_data(xml)8788      # data是个字典,它有两个元素,键值分别是'child_nodes'和'interfaces'89      if len(data['interfaces']) > 0:90          print margin + obj_name9192      for node in data['interfaces']:93          iface=data['interfaces'][node]94          show_iface(node, iface, margin+ONE_MARGIN)9596      for node in data['child_nodes']:97          if obj_name == '/':98              show_obj(bus, name, '/' + node, margin)99          else:100              show_obj(bus, name, obj_name + '/' + node, margin)101102  def show_connection(bus, name, margin):103      print margin + name104      show_obj(bus, name, '/', margin+ONE_MARGIN)105106  def usage():107      print "Usage: dteeth [--system] "108109  def main():110      try:111          opts, args = getopt.getopt(sys.argv[1:], "h", ["help", "system"])112      except getopt.GetoptError, err:113          # print help information and exit:114          print str(err) # will print something like "option -a not recognized"115          usage()116          sys.exit(2)117118      if len(args) == 0:119          usage()120          sys.exit(2)121122      use_system = False123      for o, a in opts:124          if o in ("-h", "--help"):125              usage()126              sys.exit()127          if o == "--system":128              use_system = True129          else:130              assert False, "unhandled option"131132      if use_system:133          bus=dbus.SystemBus()134      else:135          bus=dbus.SessionBus()136137      for arg in args:138          show_connection(bus, arg, "")139140  if __name__ == "__main__":141      main()

dteeth是我写的第一个超过10行的python脚本。对于熟悉python的读者,dteeth应该是很简单的。 不过我还是简单解释一下dteeth的主要逻辑。

2.3、dteeth的主要逻辑

main函数分析命令行,对命令行上指定的每个连接调用show_connection函数。 show_connection在打印连接名后调用show_obj函数。show_obj从根对象"/"开始遍历连接的对象树。

show_obj对输入对象调用Introspect方法,返回的xml数据交由_introspect_parser处理。 _introspect_parser会从xml数据中分出inerface和node。 show_obj对inerface调用show_iface显示。 show_obj对node会递归调用show_obj,实现对象树的遍历。

2.3、_introspect_parser的输出格式

_introspect_parser.process_introspection_data函数分析Introspect方法返回的xml数据。 为了了解_introspect_parser的输出格式,我们可以写个小脚本:

$ cat ti.py
#!/usr/bin/env python
import dbus
import _introspect_parser
bus=dbus.SessionBus()
obj=bus.get_object('org.freesmartphone.ogsmd', '/org/freesmartphone/GSM/Device')
iface=dbus.Interface(obj, 'org.freedesktop.DBus.Introspectable')
xml=iface.Introspect();
data = _introspect_parser.process_introspection_data(xml)
print data

可以用这个脚本直接打印process_introspection_data返回的数据。下面是整理后的输出:

{'interfaces': {u'org.freedesktop.DBus.Introspectable': {'signals': {}, 'methods': {u'Introspect': ([], [{'type': u's', 'name': u'data'}])}, 'properties': {}}, u'org.freedesktop.DBus.Properties': {'signals': {}, 'methods': {u'Set': ([{'type': u's', 'name': u'interface'}, {'type': u's', 'name': u'propname'}, {'type': u'v', 'name': u'value'}], []), u'GetAll': ([{'type': u's', 'name': u'interface'}], [{'type': u'a{sv}', 'name': u'props'}]), u'Get': ([{'type': u's', 'name': u'interface'}, {'type': u's', 'name': u'propname'}], [{'type': u'v', 'name': u'value'}])}, 'properties': {}}, u'org.freesmartphone.GSM.SMS': {'signals': {u'IncomingMessage': ([{'type': u's', 'name': None}, {'type': u's', 'name': None}, {'type': u'a{sv}', 'name': None}],)},'methods': {u'SendMessage': ([{'type': u's', 'name': u'number'}, {'type': u's', 'name': u'contents'}, {'type': u'a{sv}', 'name': u'featuremap'}], [{'type': u'i', 'name': u'arg3'}])},'properties': {}}}, 'child_nodes': []
}

所有字符串前面都有前缀u,表示这些字符串都是Unicode编码。在python中,字典用{},元组用(),列表用[]。从括号我们就能看出数据格式。

我们看到process_introspection_data返回返回一个字典。这个字典有两个映射。一个映射的键值是"interfaces",另一个映射的键值是"child_nodes"。

映射"child_nodes"的值是一个列表,列出所有子节点的名称。

映射"interfaces"的值还是一个字典。这个字典的每个映射的键值是一个接口名称。每个映射的值类型还是字典, 这个字典有3个映射,映射的键值分别是’signals’、‘methods’和’properties’,映射的值类型都是字典。

'signals’对应字典的每个键值是一个信号名称。每个映射的值类型是元组。这个元组只有一个元素,类型是列表, 即信号的参数列表。

参数列表的元素类型是字典。这个字典有2个映射,映射的键值分别是’type’和’name’。'type’是参数类型,'name’是参数名称。 映射的值类型都是字符串。

'methods’对应字典的每个键值是一个方法名称。每个映射的值类型是元组。这个元组有两个元素,类型是列表, 分别是方法的输入参数列表和输出参数列表。参数列表的元素类型和信号的参数列表相同。

我看到’properties’映射都是空的,就没有研究。

3、python基础

简单介绍一下与dteeth有关的python语法。

3.1、代码块和缩进

python用缩进来区分语句所属的代码块,从类定义、函数到for、if的代码块都是用缩进来去区分的。 没有缩进的代码块是脚本的主体代码。 一个脚本文件也被称作一个模块。 不管模块被直接运行还是被其它模块导入,主体代码都会在载入时被执行。 例如dteeth的主体代码只有两句:

   140  if __name__ == "__main__":141      main()

__xxx__这样的标志符通常是python的系统变量。如果模块被导入,__name__的值是模块的名字。 如果模块被直接执行,__name__的值是"__main__"。 我们通常在模块被直接执行时,调用主函数或模块的测试函数。

3.2、脚本文件格式

python脚本的起始行通常是:/p>

1  #!/usr/bin/env python

env是一个可以修改环境变量并执行程序的工具,它可以自动在系统路径中搜索要执行的程序。 python脚本文件必须以0A为换行符,默认仅支持ASCII字符。 如果要写中文注释(显然是不提倡的),可以在起始行后用以下语句将文件指定为utf-8编码:

2  # -*- coding: utf-8 -*-

这时,文件必须被保存为没有BOM的utf-8编码文件。

3.3、列表、元组和字典

列表类似于C的数组,列表元素用[]包括。元组是不可变的列表,元组元素用()包括。元组的元素个数和类型在创建后就不能改变了。 元组中基本类型的值是不能改变的,但如果元组的一个元素是列表,我们可以改变列表内容, 即我们可以改变元组中可变元素的内容。例如:

>>> a=(1,2,['abc'])
>>> a[2]='def'
Traceback (most recent call last):File "", line 1, in
TypeError: 'tuple' object does not support item assignment
>>> a[2][0]='def'
>>> a
(1, 2, ['def'])

字典是键-值对的集合,字典元素用{}包括。

4、结束语

本文介绍了一个叫作dteeth的python脚本。 这个脚本逻辑很简单,读者可以根据需要修改或扩充。 讲了这么多dbus,我们还没有接触C代码。下一讲,我们讨论dbus的C实例。

linux 进程间通信 dbus-glib【实例】详解三 数据类型和dteeth(类型签名type域)(层级结构:服务Service --> Node(对象、object) 等 )(附代码)相关推荐

  1. 太酷了!Linux的30 个实例详解 TOP 命令!

    英文:Linoxide 编译:Linux中国/geekpilinux.cn/article-2352-1.html Linux中的top命令显示系统上正在运行的进程.它是系统管理员最重要的工具之一.被 ...

  2. linux 进程间通信 dbus-glib【实例】详解二(下) 消息和消息总线(ListActivatableNames和服务器的自动启动)(附代码)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

  3. linux 进程间通信 dbus-glib【实例】详解二(上) 消息和消息总线(附代码)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

  4. linux 进程间通信 dbus-glib【实例】详解一(附代码)(d-feet工具使用)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

  5. linux 进程间通信 dbus-glib【实例】详解四(上) C库 dbus-glib 使用(附代码)(编写接口描述文件.xml,dbus-binding-tool工具生成绑定文件)(列集散集函数)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

  6. linux服务器怎么查看cpu配置信息,linux服务器cpu信息查看详解

    在linux系统中,提供了/proc目录下文件,显示系统的软硬件信息.如果想了解系统中CPU的提供商和相关配置信息,则可以查/proc/cpuinfo.但是此文件输出项较多,不易理解.例如我们想获取, ...

  7. java 获取oracle表结构_Java导出oracle表结构实例详解

    Java导出oracle表结构实例详解 发布于 2020-7-20| 复制链接 摘记:  Java导出oracle表结构实例详解最近用到的,因为plsql是收费的,不让用,找了很多方法终于发现了这个. ...

  8. linux查看根目录使用率,Linux 查看空间使用情况的实例详解

    Linux 查看空间使用情况的实例详解 在日常的Linux巡检中,我们会遇到文件系统目录使用空间很高的情况,例如如下利用"df -h "查看到根目录空间使用超过80%.而我们仅仅知 ...

  9. Linux 创建网页服务,Linux使用Node.js建立访问静态网页的服务实例详解

    Linux使用Node.js建立访问静态网页的服务实例详解 一.安装node.js运行所需要的环境,: 二.创建node目录(/node/www),并在目录下创建node.js服务文件server.j ...

最新文章

  1. 奇偶交错排列(DFS)
  2. 【Java 泛型】使用上下边界通配符解决泛型擦除问题
  3. 服务器开发的一些框架或者工具收集
  4. 荒岛余生最后一个包裹_荒岛余生——每个人都是一座“孤岛”
  5. UNIGUI下载文件
  6. HDU 4121 Xiangqi 模拟题
  7. Linux下显示当前目录下的全部目录或文件
  8. html5做咖啡网页素材,HTML5/CSS3咖啡品类切换动画
  9. [HDFS Manual] CH4 HDFS High Availability Using the Quorum Journal Manager
  10. 康柏川(帮别人名字作诗)
  11. BZOJ2440 [中山市选2011]完全平方数
  12. 本年度读书计划-看几本必须好好琢磨的书
  13. [牛感悟系列]JAVA(1)理解JAVA垃圾回收
  14. TensorFlow相关工具
  15. 使用Mac电脑内置的屏幕共享功能,进行远程桌面管理
  16. java手机单机游戏_手机单机游戏推荐简介
  17. Ubuntu下截图贴图软件——flameshot
  18. Eureka集群间通信
  19. 小米平板可以编程c语言吗,小米平板方便使用吗
  20. 蛋蛋读NVMe之一:为什么刘备需要NVMe

热门文章

  1. LDAP 查询基本知识
  2. 云服务器怎么创建子网,如何使用ECS实例子网划分和子网掩码
  3. 怎么恢复初始状态_汽车多少公里应该清洗节气门,不洗会有隐患吗?看看老司机怎么说...
  4. 【实用】SAP MR8M校验增强
  5. 【整理】内向交货(Inbound Delivery)
  6. REM重复制造的冲销
  7. 梅赛德斯奔驰即将为Apple Watch推出应用
  8. SAP调用WSDL报错,求解!
  9. smartforms输出格式设置说明
  10. 数据告诉你史上最年轻35000分先生到底有多强?