注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

旷世的忧伤

不与夏虫语寒,不与曲人语道,因为生命缺乏言说的条件......

 
 
 

日志

 
 

Dbus-python指南  

2014-10-12 22:08:02|  分类: Python语言 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
This tutorial requires Python 2.4 or up, and dbus-python 0.80rc4 or up.

Connecting to the Bus (连接Bus)

使用 D-Bus 的应用程序常常连接到一个 bus 服务上,这个服务在应用程序之间传递消息。想要使用 D-Bus ,你需要创建一个 Bus 对象来代表一个到 bus 服务的连接。

一般你会对两个 bus 服务感兴趣。第一个用户会话 (user login session) 应该有一个会话 bus (session bus)。以那个会话 (session) 来看 session bus 是本地的。想要连接到一个 session bus 可以通过创建一个 SessionBus 对象:

import dbus

session_bus = dbus.SessionBus()


系统 bus 是全局的,常常在启动 (boot) 的时候运行;它用来与系统服务传递信息,如 udev, NetworkManager 和 the Hardware Abstraction Layer daemon (hald)。想要连接到一个 system bus 可以通过创建一个 SystemBus 对象:

import dbus

system_bus = dbus.SystemBus()


当然,你可以在同一个应用程序里同时连接两个 bus。

为了达到特殊的目的,你也许要用到非默认的 Bus (non-default Bus), 或者根本不是一个 Bus 连接,那么就使用添加到 dbus-python 0,81.0 中的新的API。它不会出现在这里,可能会出现在其它主题的某些阶段。

Making method calls (制造一个方法调用)

D-Bus 应用程序能够输出对象让其它应用使用。为了能够使用另一个应用程序提供的对象,你需要知道:

(1) bus名称(bus name)。它标识着你想与哪个应用程序进行通讯。你会常常通过众所周知的名称(well-known name)来标识一个应用程序,它是反转域名后用 `.' 分割的字符串,例如: org.freedesktop.NetworkManager 或 com.example.WordProcessor。

(2) 对象路径(object path)。应用程序可以输出很多对象,例如, example.com 的文字处理进程会提供一个代表文字处理进程自身对象,还会为每一个打开的文档窗口都提供一个对象。或者它还可以为一个文档的每一段都提供一个对象。

     为了标识你想与谁通讯,你需要使用对象路径(object path),它是一个用 `/' 分割的字符串,就像文件名一样。例如, example.com 的文字处理进程会提供一个对像 `/' ,它代表文字进程自身, 和代其它已打开文档窗口的对象,/documents/123 和 /document/345 。

就像你期望的,你可以通过远程对象做的最主要的事情之一就是调用它们的方法。就像在 Python 中,方法有一些参数,它们会返回一个或多个值。

Proxy objects (代理对像)

为了与一个远程对象 (remote object) 通讯,你需要使用代理对象 (proxy object)。它是一个行为像代理人一样的 Python 对像,或者说就是 remote object 的标准输入 - 当你通过 proxy object 调用一个方法时,结果, dbus-python 在 remote object 上创建了一个方法调用来, 传回任何中从 remote object 的方法返回的值就像代理方法调用的返回值一样。

为了获取一个 proxy object,需要在 Bus 上调用 get_object 方法。例如,NetworkManager 拥有一个 well-known name org.freedesktop.NewworkManager 和 输出的路径为 /org/freedesktop/NetworkManager 的对象。还为每一个网络接口,如 /org/freedesktop/NetworkManager/Devices/eth0 ,都添加了一个对象。你可以取得一个代表eth0 的 proxy object ,操作如下:

import dbus
bus = dbus.SystemBus()
proxy = bus.get_object('org.freedesktop.NetworkManager',
                        '/org/freedesktop/NetworkManager/Devices/eth0')
# proxy is a dbus.proxies.ProxyObject


interfaces and methods (接口和方法)

D-Bus 使用接口来为方法提供命名空间的机制。一个接口是相关方法和信号 (后来更多在信号上) 的集合,这个集合的名称是由一系列的点分元素构成,并且它们是域名的反转。例如,每一个 NetworkManager 代表一个网络接口的对象实现为 org.freedesktop.NetworkManager.Devices,它们拥有方法 getProperties。

为了调用一个方法,在 proxy object 上调用同样名称的方法,通过 dbus_interface 关键词参数传递接口的名称。

import dbus
bus = dbus.SystemBus()
eth0 = bus.get_object('org.freedesktop.NetworkManager',
                      '/org/freedesktop/NetworkManager/Devices/eth0')
props = eth0.getProperties(dbus_interface='org.freedesktop.NetworkManager.Devices')
# props is a tuple of properties, the first of which is the object path

如果你要用同样的接口调用很多的方法,作为一个快捷的办法,你可构造一个 dbus.Interface 对像,然后在它上面调用方法,而不需要再次指定接口:

import dbus
bus = dbus.SystemBus()
eth0 = bus.get_object('org.freedesktop.NetworkManager',
                          '/org/freedesktop/NetworkManager/Devices/eth0')
eth0_dev_iface = dbus.Interface(eth0,
dbus_interface='org.freedesktop.NetworkManager.Devices')
props = eth0_dev_iface.getProperties()
# props is the same as before


See also
参考 examples/example-client.py 中的例子。在运行它之前,你需要在后台或在另一个 shell 中运行 examples/example-service.py。

Making asynchronous method calls (使用异步方法调用)

异步(非阻塞)方法调用允许同时有多个方法正在调用,允许你的应用在等待结果的时候可以做一些其它的工作。为了使用异步调用,你首先需要一个事件循环或 "main loop"。

Setting up an event loop (设置事件循环)
目前,dbus-python 唯一支持的 main loop 是 GLib 。

dbus-python 有一个全局默认的 main loop ,它是使用这个功能最容易的方法。把 GLib main loop 设置为默认,使用:

from dbus.mainloop.glib import DBusGMainLoop

DBusGMainLoop(set_as_default=True)
你必须要连接 bus 之前做些工作。

实际上常常为 pygobject 启动 main loop:

import gobject

loop = gobject.MainLoop()
loop.run()
当 loop.run() 在运行, GLib 将会在适当的时候运行你的回调函数。调用 loop.quit() 停止。

你可以在每一个连接的基础上设置一个 main loop,通过传递一个 main loop 到 Bus 构造函数。

import dbus
from dbus.mainloop.glib import DBusGMainLoop

dbus_loop = DBusGMainLoop()

bus = dbus.SessionBus(mainloop=dbus_loop)


Backwards compatibility: dbus.glib (向后兼容: dbus.glib)
在 dbus-python 0.80 之前的版本里,设置 GLib 作为默认 main loop 的方法是:

import dbus.glib

执行那个 import 语句将会自动的加载 GLib main loop 并设置它为默认。不赞成使用它,因为它是高不可见的,但是如果你想写或者理解向后兼容的代码是有用的。

The Qt main loop (Qt main loop)
PyQt v4.2 或更新的版本支持 Qt 事情循环。调用 dbus.mainloop.qt.DbusQtMainLoop 代替 dbus.mainloop.glib.DBusGMainLoop 来连接 D-Bus。否则 Qt loop 的使用将与 GLib loop 完全相同。

Making asynchronous calls (创建异步调用)
通过传递两个可调用 (callables) 的关键词参数 reply_handler 和 error_handler 到 proxy method 来生成一个异步调用。proxy method 将会立即返回 None。一段时间后,当事件循环执行时,它们中的一个将会发生:
(1)reply_handler 将会被调用,它的参数是上面方法的返回值。
(2)error_handler 将被调用,它的参数是一个代表远程异常的 DBusException 的一个实例。

See also
examples/example-async-client.py 制作异步方法调用 example-service.py 提供的服务,这个方法返回一值或一个异常。就像 examples/example-client.py,你需要先在后台或另一个 shell 中运行 examples/example-service.py。

Receiving signals (接收信号)

为了收到一个信号,Bus 需要被连接到一个事件循环 - 参考设置事件循环那章。信号只在事件循环运行的时候才能收到。

Signal matching (匹配信号)
为了对信息产生响应,你要在 Bus object 上使用 add_signal_receiver 方法。当一个匹配的信号收到后,安排好的回调函数将被调用,传入以后参数:
(1) 当收到信号时,一个可调函数 (callable) (the handler_fucntion) 将会被事件循环调用 - 它的参数是信息的参数。
(2) 信号名称,signal_name: 这里为 None (默认) 则匹配所有名称。
(3) D-Bus 接口, dbus_interface: None 是默认的,匹配所有接口。
(4) 发送者的 bus 名称 (well-known 或 unique),bus_name: None是默认的,匹配所有发送者。Well-known 名称匹配来自当前拥有那个 well-known 名称的应用程序的信号,无论应用程序是谁。
(5) 一个发送者的 object path,path: None 是默认的,匹配所有 object paths

add_signal_receiver 也有关键词参数 utf8_strings 和 byte_arrays,当调用 handler fucntion时,它们影响使用的类型。影响的方式与 byte_arrays 和 utf8_strings 选项在 proxy method 上相同。

add_signal_receiver 返回一个 SignalMatch 对像。目前,它唯一有用的公共 API 是一个没有参数移除方法,它用来移除从连接上匹配的连接。

Getting more information from a signal (从信号中获取更多信息)
你也可以安排更多的信息传递给处理函数。如果你传递了关键词参数 sender_keyword, destination_keyword, interface_keyword, member_keyword 或 path_keyword 到 connect_to_signal 方法,信号消息适当的部分将会作为关键词参数被传递给处理函数:例如,如果你使用以下实例

def handler(sender=None):
    print "got signal from %r" % sender

iface.connect_to_signal("Hello", handler, sender_keyword='sender')

一个来自 com.example.Foo 的没有参数的 Hello 信号将会被收到,处理函数将会被调用,它的参数 sender='com.example.Foo'。

String argument matching (匹配字符串参数)
如果有关键词的格式是 argn,其中 n 是一个小的非负数,它们的值必须是 unicode 对象 或 UTF-8 字符串。

Receiviing signals from a proxy object (接收来自 proxy 对象的信号)
Proxy 对象有一个特殊的方法 connect_to_signal ,当收到一个来自相应远程对象的信号时, connect_to_signal 将安排一个回调函数被调用。
(1)信号名称
(2)当收到信号时,一个可调函数 (callable) (the handler_fucntion) 将会被事件循环调用 - 它的参数是信息的参数。
(3)处理函数 (callable): 与 add_signal_receiver 相同
(4)关键词参数 dbus_interface 限定接口的名称。

dbus.Interface 对象有一个相似的 connect_to_signal 方法,但这种情况下,你不需要 dbus_interface 关键词参数,因为使用的接口已经知道了。

对于 add_signal_receiver 而言,同样的关键词参数也是可用的,就像 add_signal_receiver , 它返回一个 SignalMatch 。

你不应该只用 proxy 对象来监听信号,因为当他们创建的时候也许会激活相关的服务,但如果你为了调用方法已经有一个 proxy 对象,使用它添加信号匹配常常很方便。

See also
examples/signal-recipient.py 接收信号 - 它示范了通用信号的匹配以及 connect_to_signal 。你需要先在后台或另一个 shell 中运行 examples/signal-emitter.py。

Claiming a bus name (声名一个 bus name)

FIXME describe BusName - perhaps fix its API first?

The unique-instance idiom
FIXME provide exemplary code, put it in examples


Exporting objects (导出对象)

在 D-Bus 上让另外一个应用程序可用的对像称作导出 (exported)。所有的 dbus.service.Object 的子类是自动被 exported。

为了 export 对象, Bus 需要连接到事件循环 - 参考设置事件循环那章。只有在事件循环运行时,导出方法也才会被调用,队列中的信号才会被传递。

Inheriting from dbus.service.Object (继承 dbus.service.Object)
在 Bus 导出一个对象,它仅是 dbus.service.Object 的子集。这个对象期待一个 BusName 或 Bus 对象以及 object-path ,来传递给它的构造函数:为这些要使用的信息做准备。例如:

class Example(dbus.service.Object):
    def __init__(self, object_path):
        dbus.service.Object.__init__(self, dbus.SessionBus(), path)


这个对象会自动支持 introspection ,但不做任何特别的事情。为了修正它,你需要导出一些方法和信号。

FIXME also mention dbus.gobject.ExportedGObject once I've written it

Exporting methods with dbus.service.method (使用 dbus.service.method 导出方法)
为了导出方法,使用 dbus.service.method 操作,例如:

class Example(dbus.service.Object):
    def __init__(self, object_path):
        dbus.service.Object.__init__(self, dbus.SessionBus(), path)

    @dbus.service.method(dbus_interface='com.example.Sample',
                         in_signature='v', out_signature='s')
    def StringifyVariant(self, variant):
        return str(variant)

in_signature 和 out_signature 是 D-Bus 的标识字符串,描述数据的类型。

像关键词显示的,你可以传递 utf8_string 和 byte_arrays 关键词参数,当你通过 D-Bus 调用方法时,它将影响传递参数的类型。 byte_arrays 和 utf8_strings 选项以同样的方式影响返回值。

你可以找到一个简单的例子 examples/example-service.py ,我们先前用来它来示范 examples/example-client.py 。

Finding out the caller's bus name
方法描述接受 sender_keyword 关键词参数。如果你把它设置为一个字符串,发送者的唯一 bus 名称将作为一个关键词参数传递到描述方法:

class Example(dbus.service.Object):
    def __init__(self, object_path):
        dbus.service.Object.__init__(self, dbus.SessionBus(), path)

    @dbus.service.method(dbus_interface='com.example.Sample',
                         in_signature='', out_signature='s',
                         sender_keyword='sender')
    def SayHello(self, sender=None):
        return 'Hello, %s!' % sender
        # -> something like 'Hello, :1.1!'


Asynchronous method implementations (异步方法的实现)
FIXME and also add an example, perhaps examples/example-async-service.py

Emitting signals with dbus.service.signal

To export a signal, use the decorator dbus.service.signal; to emit that signal, call the decorated method. The decorated method can also contain code which will be run when called, as usual. For example:

class Example(dbus.service.Object):
    def __init__(self, object_path):
        dbus.service.Object.__init__(self, dbus.SessionBus(), path)

    @dbus.service.signal(dbus_interface='com.example.Sample',
                         signature='us')
    def NumberOfBottlesChanged(self, number, contents):
        print "%d bottles of %s on the wall" % (number, contents)

e = Example('/bottle-counter')
e.NumberOfBottlesChanged(100, 'beer')
# -> emits com.example.Sample.NumberOfBottlesChanged(100, 'beer')
#    and prints "100 bottles of beer on the wall"


The signal will be queued for sending when the decorated method returns - you can prevent the signal from being sent by raising an exception from the decorated method (for instance, if the parameters are inappropriate). The signal will only actually be sent when the event loop next runs.

Example
examples/example-signal-emitter.py emits some signals on demand when one of its methods is called. (In reality, you'd emit a signal when some sort of internal state changed, which may or may not be triggered by a D-Bus method call.)
当发送信号的方法之一被调用, examples/example-signal-emitter.py 会按要求发送一些信号。

License for this document

Copyright 2006-2007 Collabora Ltd.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

本文内容摘自:http://fanrenhao.blog.51cto.com/3961213/807935

参考资料:
http://fanrenhao.blog.51cto.com/3961213/807935
http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html
  评论这张
 
阅读(39)| 评论(1)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018