Jump to Navigation

在PyQt5中使用Qt DBus的延时响应返回

在PyQt5中使用Qt DBus的延时响应返回

### dbus介绍
dbus是一种现代linux系统中的本机RPC调用实现,实现了程序间的松耦合依赖。

### RPC调用
RPC调用可分为同步调用和异步调用。
常用的同步调用很容易理解,就是调用并一直等待RPC服务器端的返回值。
异步调用,是针对某次耗时的RPC调用而言,像文件操作,或者是网络操作,或者计算操作。
如果再一直等待服务器端的返回,客户端的效率将非常低下。

### 原始DBus的方式
dbus是使用了异步IO回调方式,所以并不存在所谓的延时响应返回问题。
因为所有的调用都可以看作是异步的,延时的。
不过dbus提供了一个超时机制,如果超时,则dbus调用端不再接收响应返回值了。

### Qt DBus的方式
在Qt中,把DBus的服务,调用响应封装成为Qt的QObject和slots,从而简化DBus的使用。
同时,默认情况下,Qt还把对应slots的返回作为DBus调用结束的标志。
这样就引入一个问题,如果在这个slots中无法立即完成一个dbus调用,应该怎么处理?

当然,Qt考虑到这种情况,也提供了一个api方案供使用,那就是Delayed Replies。
大概意思就是,在对应的slots中,把这次DBus调用设置为延时响应返回,保存当前状态。
然后在未来某个时候,根据之前保存的状态显式调用QDBusConnection::send()方法,发送响应结果。

注意:在Qt 5.5的文档中,关于Delayed Replies的示例有个bug,就是在对应的slots中不能调用QDBusConnection::send(),否则客户端就以为执行已经完成。
file:///usr/share/doc/qt/qtdbus/qdbusdeclaringslots.html#delayed-replies

当然,对于调用端也有要求,就是要使用QDBusInterface::asyncCallxxx方法,表示这是个异步调用。
使用类似QFuture功能的QDBusPendingCallWatcher接口异步调用的响应结果,但并不阻塞当前的调用。

### PyQt5 Qt DBus示例

delaycli.py:

  1. sessbus = QDBusConnection.sessionBus()
  2. SERVICE_NAME = 'io.qtc.delaysrv'
  3.  
  4. iface = QDBusInterface(SERVICE_NAME, '/', '', sessbus)
  5.  
  6. pcall = iface.asyncCall('ahello', 'a1', 'a2', 3)
  7. def callFinishedSlot(watcher):
  8. qDebug(str(watcher))
  9.  
  10. watcher = QDBusPendingCallWatcher(pcall)
  11. watcher.finished.connect(callFinishedSlot)

delaysrv.py:

  1. sessbus = None
  2. class DelayDemoService(QObject):
  3. def __init__(self, parent = None):
  4. super(DelayDemoService, self).__init__(parent)
  5. self._reply = None
  6.  
  7.  
  8. @pyqtSlot(QDBusMessage, result=int)
  9. def hello(self, message):
  10. qDebug(str(message))
  11. qDebug(str(message.arguments()))
  12. return 456
  13.  
  14. @pyqtSlot(QDBusMessage, result=str)
  15. def ahello(self, message):
  16. message.setDelayedReply(True)
  17. dreply = message.createReply("789")
  18. self._reply = dreply
  19.  
  20. QTimer.singleShot(5000, self.tshot) # 模拟延时响应
  21. return "123"
  22.  
  23. def tshot(self):
  24. bret = sessbus.send(self._reply)
  25. qDebug(str(bret))
  26.  
  27. sessbus = QDBusConnection.sessionBus()
  28.  
  29. SERVICE_NAME = 'io.qtc.delaysrv'
  30. sessbus.registerService(SERVICE_NAME)
  31.  
  32. ddsvc =DelayDemoService()
  33. bret = sessbus.registerObject("/",ddsvc, QDBusConnection.ExportAllSlots)

示例中只写列出了核心代码,请自行添加QCoreApplication相关代码来执行测试。
这里也有完整的代码,供参考:

### Qt DBus中的广播信号

添加新评论

Plain text

  • 不允许HTML标记。
  • 自动将网址与电子邮件地址转变为链接。
  • 自动断行和分段。
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.


Main menu 2

Story | by Dr. Radut