我想制作一个包含两部分的程序。监听器(服务器,如果您愿意)和发送者(客户端)。我做了一些研究,并了解到这是通过方法程序员调用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。
答案 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:])