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; }
关键修改点
- 在
ManagerProxy中添加std::map<sdbus::ObjectPath, std::unique_ptr<TestObjProxy>> m_objectProxies,用于存储每个对象路径对应的proxy实例 onInterfacesAdded中不再创建局部TestObjProxy,而是通过std::make_unique创建实例并存入容器onInterfacesRemoved中移除对应路径的proxy实例,避免内存泄漏
内容的提问来源于stack exchange,提问作者Robotex
相关产品推荐
相关产品推荐

