简单(但具体)监听器和发送者Python 3 DBus示例

时间:2014-02-15 05:33:53

标签: python linux python-3.x ipc dbus

我想制作一个包含两部分的程序。监听器(服务器,如果您愿意)和发送者(客户端)。我做了一些研究,并了解到这是通过方法程序员调用IPC(进程间通信)完成的;我相信你知道这意味着什么,我只是扩展这个缩写词,以便你知道我认为这并不意味着互联网宠物食人族(或其他一些不相关的不愉快的东西)。

我读到了实现这一目标的一个好方法是使用dbus。所以我对dbus进行了一些研究,现在我只是感到困惑。显然你可以用dbus做很多事情,比如向Gnome Shell发送通知或者与网络管理员交谈。我不想做那些事情!我只想制作两个相互通信的简单程序。除此之外,一些教程和文档显示了python 2的示例,一些使用3,一些导入dbus和一些导入Gio!我发现的很多信息都在我脑海中,这也损害了我的努力。

有人会如此善良地向我展示一个简单,优雅的例子,说明如何制作一个基本上这样做的程序:

$ ./server
Server is not running yet. Putting on listening ears.
$ ./client Hi
server: a client said "Hi"
$ ./server
Server is already running.
$ ./server stop
Server exiting...
$ ./client Do a barrel roll
client: No one can hear me!!

这是一个简单的会话(当然使用bash shell)。我想使用Python 3和任何dbus绑定是最合适的(我猜这将是gi.repository)。为了澄清,这将适用于Linux。

1 个答案:

答案 0 :(得分:9)

在python3中没有很多关于dbus的文档,但是我设法弄清楚了所以我将在这里记录它:与所有python2示例的主要区别在于用{{替换import gobject 1}}

您可以在the dbus-python examples directory中找到更多示例(使用的功能超出我的要求)。

我没有在服务器中实现自我背景,因为这种守护进程的风格最近已经过时了。

common.py:

import gi.repository.GLib

server.py:

# well-known name for our program
ECHO_BUS_NAME = 'com.stackoverflow.question_21793826.EchoService'

# interfaces implemented by some objects in our program
ECHO_INTERFACE = 'com.stackoverflow.question_21793826.EchoInterface'
QUIT_INTERFACE = 'com.stackoverflow.question_21793826.QuitInterface'

# paths to some objects in our program
ECHO_OBJECT_PATH = '/EchoServerObject'

client.py:

#!/usr/bin/env python3

# standard includes
import sys

# dbus includes
import gi.repository.GLib
import dbus
import dbus.service
import dbus.mainloop.glib

# project includes
import common


class EchoServerObject(dbus.service.Object):

    # TODO it would be nice to make a better decorator using annotations:
    #   def foo(self, a: 's', b: 's') -> '': pass
    # but the existing dbus decorator does its own reflection which
    # fails if there are any annotations (or keyword-only arguments)
    @dbus.service.method(common.ECHO_INTERFACE,
            in_signature='s', out_signature='')
    def echo(self, message):
        message = str(message) # get rid of subclass for repr
        print('server: a client said %r' % message)

    @dbus.service.method(common.QUIT_INTERFACE,
            in_signature='', out_signature='')
    def quit(self):
        # this should be a separate object, but I'm
        # showing how one object can have multiple interfaces
        self.mainloop.quit()

def stop():
    bus = dbus.SessionBus()

    proxy = bus.get_object(common.ECHO_BUS_NAME, common.ECHO_OBJECT_PATH)
    iface = dbus.Interface(proxy, common.QUIT_INTERFACE)

    iface.quit()

def server():
    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

    bus = dbus.SessionBus()
    try:
        name = dbus.service.BusName(common.ECHO_BUS_NAME, bus, do_not_queue=True)
    except dbus.NameExistsException:
        sys.exit('Server is already running.')
    else:
        print('Server is not running yet. Putting on listening ears.')
    echo = EchoServerObject(bus, common.ECHO_OBJECT_PATH)

    mainloop = gi.repository.GLib.MainLoop()
    echo.mainloop = mainloop
    mainloop.run()

def main(exe, args):
    if args == ['stop']:
        stop()
    elif not args:
        server()
    else:
        sys.exit('Usage: %s [stop]' % exe)

if __name__ == '__main__':
    main(sys.argv[0], sys.argv[1:])