sdbus-c++:客户端对来自服务器的信号没有反应

问题描述 投票:0回答:1

我正在尝试创建没有 UI 和 GUI 应用程序来配置它的守护程序。该应用程序应该向守护进程发送命令并显示更新的信息。我正在尝试使用 DBus 和 sdbus-c++ 库。

客户端对服务器信号没有反应的问题。它忽略 PropertiesChanged 信号以及我的自定义信号。但我在 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 的 InterfaceAdded 和 InterfaceRemoved,但忽略 ObjectProxy 的每个信号。

那么,我做错了什么?

生成绑定 XML:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/test/sdbuscpp/TestApp/TestObj">
    <interface name="test.sdbuscpp.TestApp.TestObj">
        <property name="StringProperty" type="s" access="read"/>

    <property name="RandomNumber" type="t" access="readwrite">
        <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true" />
    </property>

    <signal name="Updated">
        <arg name="Property" type="s" />
    </signal>
    </interface>
</node>

服务器代码:

#include "daemon-glue.h"

#include <sdbus-c++/sdbus-c++.h>
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <signal.h>
#include <syslog.h>
#include <sys/stat.h>


class ManagerAdaptor : public sdbus::AdaptorInterfaces< sdbus::ObjectManager_adaptor >
{
public:
    ManagerAdaptor(sdbus::IConnection& connection, std::string path)
    : AdaptorInterfaces(connection, std::move(path))
    {
    
        registerAdaptor();
    }

    ~ManagerAdaptor()
    {
        unregisterAdaptor();
    }
};

class TestObjAdaptor final : public sdbus::AdaptorInterfaces< test::sdbuscpp::TestApp::TestObj_adaptor,
                                                sdbus::ManagedObject_adaptor,
                                                sdbus::Properties_adaptor >
{
public:
    TestObjAdaptor(sdbus::IConnection& connection, std::string path, std::string someString, uint64_t someRandomNumber)
    : AdaptorInterfaces(connection, std::move(path))
    , someString(std::move(someString))
    , someRandomNumber(someRandomNumber)
    {
    registerAdaptor();
        emitInterfacesAddedSignal({test::sdbuscpp::TestApp::TestObj_adaptor::INTERFACE_NAME});
    }

    ~TestObjAdaptor()
    {
        emitInterfacesRemovedSignal({test::sdbuscpp::TestApp::TestObj_adaptor::INTERFACE_NAME});
        unregisterAdaptor();
    }

    uint64_t RandomNumber() override
    {
        return someRandomNumber;
    }

    void RandomNumber(const uint64_t& number) override
    {
    someRandomNumber = number;
    
    emitPropertiesChangedSignal(test::sdbuscpp::TestApp::TestObj_adaptor::INTERFACE_NAME, {"RandomNumber"});
    emitUpdated("RandomNumber");
    }

    std::string StringProperty() override
    {
        return someString;
    }

private:
    std::string someString;
    uint64_t someRandomNumber;
};

int main()
{
    std::srand(std::time(nullptr));

    auto connection = sdbus::createSessionBusConnection();
    connection->requestName("test.sdbuscpp.TestApp");
    connection->enterEventLoopAsync();

    auto manager = std::make_unique<ManagerAdaptor>(*connection, "/test/sdbuscpp/TestApp");
    
    std::unique_ptr<TestObjAdaptor> ObjArray[] = {
    std::make_unique<TestObjAdaptor>(*connection, "/test/sdbuscpp/TestApp/TestObj/Obj1", "Obj1", std::rand()),
    std::make_unique<TestObjAdaptor>(*connection, "/test/sdbuscpp/TestApp/TestObj/Obj2", "Obj2", std::rand()),
    std::make_unique<TestObjAdaptor>(*connection, "/test/sdbuscpp/TestApp/TestObj/Obj3", "Obj3", std::rand())
    };

    while (true)
    {
        for (const auto& Obj : ObjArray)
    {
        Obj->RandomNumber(std::rand());
    }

    std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    for (auto& Obj : ObjArray)
    {
    Obj.reset();
    }

    connection->releaseName("test.sdbuscpp.TestApp");
    connection->leaveEventLoop();

    return EXIT_SUCCESS;
}

客户代码:

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

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();
    }

    virtual 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;

        // Parse and print some more info
        if (interface != test::sdbuscpp::TestApp::TestObj_proxy::INTERFACE_NAME)
    {
            return;
        }
        
    std::cout << "Changed properties:" << std::endl;
    for (const std::pair<std::string, sdbus::Variant>& property : changed_properties)
    {
        std::cout << property.first << std::endl;
    }
    
    std::cout << "Invalidated properties:" << std::endl;
    for (const std::string& property : invalidated_properties)
    {
        std::cout << property << std::endl;
    }
    }

    virtual 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()
    {
        std::map<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>> objectsInterfacesAndProperties;
        objectsInterfacesAndProperties = GetManagedObjects();

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

        for (const std::pair<sdbus::ObjectPath, std::map<std::string, std::map<std::string, sdbus::Variant>>>& 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;

        // Parse and print some more info
        auto objInterface = interfacesAndProperties.find(test::sdbuscpp::TestApp::TestObj_proxy::INTERFACE_NAME);
        if (objInterface == interfacesAndProperties.end()) {
            return;
        }
        const auto& properties = objInterface->second;
        // get a property which was passed as part of the signal.
        const auto& name = properties.at("StringProperty").get<std::string>();
        // or create a proxy instance to the newly added object.
        TestObjProxy obj(m_connection, m_destination, 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;
    }

    

    sdbus::IConnection& m_connection;
    std::string m_destination;
};

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;
}
c++ linux dbus
1个回答
0
投票

我找到了问题的根源。

该问题是由于在堆栈上而不是在 ManagerProxy::onInterfacesAdded 中的堆上创建 TestObjProxy 引起的。因此,该函数返回后该对象将被删除,并且没有人监听更新信号。

在动态分配的内存中创建对象后,问题就消失了。

© www.soinside.com 2019 - 2024. All rights reserved.