簡體   English   中英

DBUS 通信中的 NoReply 異常

[英]NoReply Exception in DBUS communication

我正在開發一個異步通信腳本,它將充當本機反應應用程序和另一個代理之間的中間人。 為此,我使用 python 和 DBUS 來實現兩者之間的通信。

為實現這一點,我們創建了兩個進程,一個用於 BLE,一個用於與代理通信。 在代理立即回復(通過非阻塞調用)的情況下,通信始終按預期進行。 對於我們附加到信號以持續監視更新狀態的情況,此錯誤大部分時間發生在過程中的隨機點:

dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NoReply: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.

我分別測試了 BLE 進程和代理進程,它們按預期工作。

我目前懷疑它可能與系統總線上的消息“崩潰”或某些競爭條件有關,但我們不確定如何驗證這一點。

關於可能導致此問題的原因或如何避免的任何建議?

為了完整起見,我附上了 class 的簡化版本,用於處理與代理的通信。

import multiprocessing
from enum import Enum
import dbus
import dbus.mainloop.glib
from dbus.proxies import ProxyObject
from gi.repository import GLib
from omegaconf import DictConfig
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)


class ClientUpdateStatus(Enum):
    SUCCESS = 0
    PENDING = 1
    IN_PROGRESS = 2
    FAILED = 3

class DBUSManager:

    GLIB_LOOP = GLib.MainLoop()
    COMMUNICATION_QUEUE = multiprocessing.Queue()
    
    def __init__(self, config: DictConfig) -> None:
        
        dbus_system_bus = dbus.SystemBus()
        
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
        self._config = config
        
        self._dbus_object = dbus_system_bus.get_object(self._config['dbus_interface'],
                                                            self._config['dbus_object_path'], introspect=False)

    def get_version(self) -> str:

        version = self._dbus_object.GetVersion("clientSimulator", dbus_interface=self._config['dbus_interface'])
        return version

    def check_for_update(self) -> str:
        update_version = self._dbus_object.CheckForUpdate("clientSimulator",
                                                               dbus_interface=self._config['dbus_interface'])
        return update_version

    def run_update(self) -> ClientUpdateStatus:
        raw_status = self._dbus_object.ExecuteUpdate(dbus_interface=self._config['dbus_interface'])
        
        update_status = ClientUpdateStatus(raw_status)
        
        # Launch listening process
        signal_update_proc = multiprocessing.Process(target=DBUSManager.start_listener_process,
                                                     args=(self._dbus_object, self._config['dbus_interface'],))
        signal_update_proc.start()

        while True:
            raw_status = DBUSManager.COMMUNICATION_QUEUE.get()
            update_status = ClientUpdateStatus(raw_status)
            
            if ClientUpdateStatus.SUCCESS == update_status:
                break

        signal_update_proc.join()

        return update_status

    @staticmethod
    def start_listener_process(dbus_object: ProxyObject, dbus_interface: str) -> None:
       
        dbus_object.connect_to_signal("UpdateStatusChanged", DBUSManager.status_change_handler,
                                           dbus_interface=dbus_interface)
        # Launch loop to acquire signals
        DBUSManager.GLIB_LOOP.run()  # This listening loop exits on GLIB_LOOP.quit()

    @staticmethod
    def status_change_handler(new_status: int) -> None:
        DBUSManager.COMMUNICATION_QUEUE.put(new_status)
        if ClientUpdateStatus.SUCCESS == ClientUpdateStatus(new_status):
            DBUSManager.GLIB_LOOP.quit()

在這個階段,我建議做一個dbus-monitor來查看代理和 BLE 是否正確地響應請求。

也許為了將來幫助其他人,我還沒有找到解決方案,但至少找到了一種解決方法。 我們在項目的各個地方都遇到過這個問題,通常有幫助的是,不要問我為什么,總是重新實例化所有需要的 dbus 對象。 因此,與其使用具有系統總線變量self._system_bus = dbus.SystemBus()或接口變量self._manager_interface = dbus.Interface(proxy_object, "org.freedesktop.DBus.ObjectManager")的單個 class,我們總是重新-instate他們。

如果有人知道問題出在哪里,我很高興聽到。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM