DBus 是一个高级的消息传递系统,它允许应用程序和组件通过消息进行通信。它通常用于进程间通信(IPC),相同或不同语言的程序或程序模块都能使用它。在 Python 中,我们可以利用 DBus 实现两个程序(发送者和接收者)之间的通信。
2、解决方案
我们使用 Python 3 和 DBus bindings(使用 gi.repository.GLib)来实现一个发送和接收程序,以便进行基本的通信。代码分为以下几个部分:
common.py:包含一些公共变量和常量,例如,设置我们的程序的名称、接口和路径。
server.py:包含服务器端程序的逻辑。它创建一个 DBus 服务对象(EchoServerObject),实现两个接口(EchoInterface 和 QuitInterface),提供回显消息和退出服务的函数。
client.py:包含客户端程序的逻辑。它获取 DBus 服务并调用服务对象的方法来发送消息。
为了让程序工作,需要先启动服务器端(server.py),然后启动客户端(client.py)发送消息。
完整的代码示例:
common.py:
# 设置我们的程序的名称、接口和路径。
ECHO_BUS_NAME = 'com.stackoverflow.question_21793826.EchoService'
ECHO_INTERFACE = 'com.stackoverflow.question_21793826.EchoInterface'
QUIT_INTERFACE = 'com.stackoverflow.question_21793826.QuitInterface'
ECHO_OBJECT_PATH = '/EchoServerObject'
server.py:
#!/usr/bin/env python3
# 导入必要的库。
import sys
import gi.repository.GLib
import dbus
import dbus.service
import dbus.mainloop.glib
import common
class EchoServerObject(dbus.service.Object):
# 定义回显消息的方法。
@dbus.service.method(common.ECHO_INTERFACE,
in_signature='s', out_signature='')
def echo(self, message):
message = str(message) # 确保消息是字符串类型。
print('server: a client said %r' % message)
# 定义退出程序的方法。
@dbus.service.method(common.QUIT_INTERFACE,
in_signature='', out_signature='')
def quit(self):
# 这应该是一个单独的对象,但我们这里展示一个对象可以有多个接口的情况。
self.mainloop.quit()
def stop():
# 获取 DBus 会话总线。
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 主循环。
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
# 获取 DBus 会话总线。
bus = dbus.SessionBus()
try:
# 注册 DBus 服务名称。
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:])
client.py:
#!/usr/bin/env python3
# 导入必要的库。
import sys
import dbus
import common
def client(mes):
# 获取 DBus 会话总线。
bus = dbus.SessionBus()
try:
# 获取代理对象。
proxy = bus.get_object(common.ECHO_BUS_NAME, common.ECHO_OBJECT_PATH)
except dbus.DBusException as e:
# 处理异常情况。
if e._dbus_error_name != 'org.freedesktop.DBus.Error.ServiceUnknown':
raise
if e.__context__._dbus_error_name != 'org.freedesktop.DBus.Error.NameHasNoOwner':
raise
print('client: No one can hear me!!')
else:
# 获取接口对象。
iface = dbus.Interface(proxy, common.ECHO_INTERFACE)
# 调用服务对象的回显消息方法。
iface.echo(mes)
def main(exe, args):
if args:
client(' '.join(args))
else:
# 输出错误用法信息并退出程序。
sys.exit('Usage: %s message...' % exe)
if __name__ == '__main__':
main(sys.argv[0], sys.argv[1:])
运行程序:
- 启动服务器程序:
python3 server.py
- 启动客户端程序,发送消息:
python3 client.py Hello, world!
- 观察服务器端的输出:
server: a client said "Hello, world!"
- 停止服务器程序:
python3 server.py stop