You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

sdbus-c++客户端无法响应服务端信号问题求助

sdbus-c++客户端无法捕获DBus对象的PropertiesChanged和自定义信号

问题现象

开发基于DBus+sdbus-c++的无UI守护进程与GUI配置应用,两者通过DBus通信实现指令发送与更新展示。当前服务端能正常发出PropertiesChanged和自定义Updated信号(可通过dbus-monitor确认),但客户端仅能接收ObjectManager的InterfaceAdded/InterfaceRemoved信号,无法响应对象级的上述信号。

dbus-monitor捕获到的服务端信号:

signal time=1712935168.329878 sender=:1.25 -> destination=(null destination) serial=20 path=/test/sdbuscpp/TestApp/TestObj/Obj2; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
   string "test.sdbuscpp.TestApp.TestObj"
   array [
      dict entry(
         string "RandomNumber"
         variant             uint64 1881716734
      )
   ]
   array [
   ]
signal time=1712935168.329894 sender=:1.25 -> destination=(null destination) serial=21 path=/test/sdbuscpp/TestApp/TestObj/Obj2; interface=test.sdbuscpp.TestApp.TestObj; member=Updated
   string "RandomNumber"

问题根源

客户端ManagerProxy的onInterfacesAdded方法中,创建的TestObjProxy是局部变量:

TestObjProxy obj(m_connection, m_destination, objectPath);

该对象在方法执行完毕后立即被销毁,后续服务端发出信号时,已无对应的proxy实例绑定到DBus连接上处理信号,因此信号被忽略。而ManagerProxy通过std::unique_ptr持有,生命周期贯穿整个客户端运行过程,所以能正常接收信号。

解决方案

在ManagerProxy中维护一个容器,存储所有TestObjProxy实例,延长其生命周期至客户端运行期间。同时在onInterfacesRemoved方法中清理对应对象,避免内存泄漏。

修改后的客户端代码

#include "gui-glue.h"
#include <sdbus-c++/sdbus-c++.h>
#include <iostream>
#include <thread>
#include <map>
#include <memory>

class TestObjProxy final : public sdbus::ProxyInterfaces< test::sdbuscpp::TestApp::TestObj_proxy, sdbus::Properties_proxy >
{
public:
    TestObjProxy(sdbus::IConnection& connection, std::string destination, std::string path)
    : ProxyInterfaces(connection, std::move(destination), std::move(path))
    {
        registerProxy();
    }

    ~TestObjProxy()
    {
        unregisterProxy();
    }

    void onPropertiesChanged( const std::string& interface, const std::map<std::string, sdbus::Variant>& changed_properties, const std::vector<std::string>& invalidated_properties) override
    {
        std::cout << interface << " changed" << std::endl;

        if (interface != test::sdbuscpp::TestApp::TestObj_proxy::INTERFACE_NAME)
        {
            return;
        }
        
        std::cout << "Changed properties:" << std::endl;
        for (const auto& property : changed_properties)
        {
            std::cout << property.first << std::endl;
        }
        
        std::cout << "Invalidated properties:" << std::endl;
        for (const auto& property : invalidated_properties)
        {
            std::cout << property << std::endl;
        }
    }

    void onUpdated(const std::string& Property) override
    {
        std::cout << "Property updated: " << Property << std::endl;
    }

};

class ManagerProxy final : public sdbus::ProxyInterfaces< sdbus::ObjectManager_proxy >
{
public:
    ManagerProxy(sdbus::IConnection& connection, const std::string& destination, std::string path)
    : ProxyInterfaces(connection, destination, std::move(path))
    , m_connection(connection)
    , m_destination(destination)
    {
        registerProxy();
    }

    ~ManagerProxy()
    {
        unregisterProxy();
    }

    void handleExistingObjects()
    {
        auto objectsInterfacesAndProperties = GetManagedObjects();

        std::cout << objectsInterfacesAndProperties.size() << " objects awaits" << std::endl;

        for (const auto& objectPair : objectsInterfacesAndProperties) {
            onInterfacesAdded(objectPair.first, objectPair.second);
        }
    }

private:
    void onInterfacesAdded( const sdbus::ObjectPath& objectPath
            , const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties) override
    {
        std::cout << objectPath << " added:\t";
        for (const auto& interfacePair : interfacesAndProperties) {
            std::cout << interfacePair.first << " ";
        }
        std::cout << std::endl;

        auto objInterface = interfacesAndProperties.find(test::sdbuscpp::TestApp::TestObj_proxy::INTERFACE_NAME);
        if (objInterface == interfacesAndProperties.end()) {
            return;
        }
        const auto& properties = objInterface->second;
        const auto& name = properties.at("StringProperty").get<std::string>();
        
        // 将TestObjProxy实例存入容器,延长生命周期
        m_objectProxies[objectPath] = std::make_unique<TestObjProxy>(m_connection, m_destination, objectPath);
        auto& obj = *m_objectProxies[objectPath];
        std::cout << "Object " << name << " num " << obj.RandomNumber() << std::endl;
    }

    void onInterfacesRemoved( const sdbus::ObjectPath& objectPath
            , const std::vector<std::string>& interfaces) override
    {
        std::cout << objectPath << " removed:\t";
        for (const auto& interface : interfaces) {
            std::cout << interface << " ";
        }
        std::cout << std::endl;

        // 清理对应对象
        if (interfaces.contains(test::sdbuscpp::TestApp::TestObj_proxy::INTERFACE_NAME))
        {
            m_objectProxies.erase(objectPath);
        }
    }

    sdbus::IConnection& m_connection;
    std::string m_destination;
    // 存储TestObjProxy实例,维护其生命周期
    std::map<sdbus::ObjectPath, std::unique_ptr<TestObjProxy>> m_objectProxies;
};

int main()
{
    auto connection = sdbus::createSessionBusConnection();

    auto managerProxy = std::make_unique<ManagerProxy>(*connection, "test.sdbuscpp.TestApp", "/test/sdbuscpp/TestApp");
    try {
        managerProxy->handleExistingObjects();
    }
    catch (const sdbus::Error& e) {
        if (e.getName() == "org.freedesktop.DBus.Error.ServiceUnknown") {
            std::cout << "Waiting for server to start ..." << std::endl;
        }
    }

    std::cout << "enter event loop" << std::endl;
    connection->enterEventLoopAsync();

    while(true);

    std::cout << "exit event loop" << std::endl;
    return 0;
}

关键修改点

  1. 在ManagerProxy中添加std::map<sdbus::ObjectPath, std::unique_ptr<TestObjProxy>> m_objectProxies,用于存储每个对象路径对应的proxy实例
  2. onInterfacesAdded中不再创建局部TestObjProxy,而是通过std::make_unique创建实例并存入容器
  3. onInterfacesRemoved中移除对应路径的proxy实例,避免内存泄漏

内容的提问来源于stack exchange,提问作者Robotex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 23:49:52