3

当我在同一进程中创建 D-Bus 服务器(通过 g_bus_own_name())和客户端(使用 g_dbus_proxy_new())然后调用 g_dbus_proxy_call_sync() 时,它永远不会返回。但是,如果服务器和客户端处于不同的进程中,则一切正常。

以下代码说明了我的问题(我在这里使用 giomm C++ 绑定):

文件 main.cc:

#include <giomm.h>
#include <thread>

int server_main();
int client_main();

int main() {
    Gio::init();
    std::thread thr_server([](){ server_main(); });
    sleep(1);  // give some time to server to register
    std::thread thr_client([](){ client_main(); });
    sleep(10);  // wait for the client to finish
}

文件 server.cc:

#include <giomm.h>
#include <iostream>

namespace {
static Glib::RefPtr<Gio::DBus::NodeInfo> introspection_data;

static Glib::ustring introspection_xml =
  "<node name='/org/glibmm/DBusExample'>"
  "  <interface name='org.glibmm.DBusExample'>"
  "    <method name='Method'>"
  "    </method>"
  "  </interface>"
  "</node>";

guint registered_id = 0;
}

static void on_method_call(const Glib::RefPtr<Gio::DBus::Connection>& /* connection */,
  const Glib::ustring& /* sender */, const Glib::ustring& /* object_path */,
  const Glib::ustring& /* interface_name */, const Glib::ustring& method_name,
  const Glib::VariantContainerBase& parameters,
  const Glib::RefPtr<Gio::DBus::MethodInvocation>& invocation)
{
  if(method_name == "Method") {
    std::cout << "Method was called\n";
  }      
}

const Gio::DBus::InterfaceVTable interface_vtable(sigc::ptr_fun(&on_method_call));

void on_bus_acquired(const Glib::RefPtr<Gio::DBus::Connection>& connection, const Glib::ustring& /* name */)
{
  std::cout << "on_bus_acquired\n";      
  try {
    registered_id = connection->register_object("/org/glibmm/DBusExample",
      introspection_data->lookup_interface(),
      interface_vtable);
  }
  catch(const Glib::Error& ex) {
    std::cerr << "Registration of object failed." << std::endl;
  }

  return;
}

void on_name_acquired(const Glib::RefPtr<Gio::DBus::Connection>& /* connection */, const Glib::ustring& /* name */)
{}

void on_name_lost(const Glib::RefPtr<Gio::DBus::Connection>& connection, const Glib::ustring& /* name */) {
  connection->unregister_object(registered_id);
}

int server_main()
{
  try {
    introspection_data = Gio::DBus::NodeInfo::create_for_xml(introspection_xml);
  }
  catch(const Glib::Error& ex) {
    std::cerr << "Unable to create introspection data: " << ex.what() <<
      "." << std::endl;
    return 1;
  }

  const guint id = Gio::DBus::own_name(Gio::DBus::BUS_TYPE_SESSION,
    "org.glibmm.DBusExample",
    sigc::ptr_fun(&on_bus_acquired),
    sigc::ptr_fun(&on_name_acquired),
    sigc::ptr_fun(&on_name_lost));

  //Keep the service running
  auto loop = Glib::MainLoop::create();
  loop->run();

  Gio::DBus::unown_name(id);

  return EXIT_SUCCESS;
}

文件client.cc:

#include <giomm.h>
#include <iostream>

Glib::RefPtr<Glib::MainLoop> loop;

// A main loop idle callback to quit when the main loop is idle.
bool on_main_loop_idle() {
  std::cout << "loop_idle\n";
  loop->quit();
  return false;
}

void on_dbus_proxy_available(Glib::RefPtr<Gio::AsyncResult>& result)
{
  auto proxy = Gio::DBus::Proxy::create_finish(result);

  if(!proxy) {
    std::cerr << "The proxy to the user's session bus was not successfully "
      "created." << std::endl;
    loop->quit();
    return;
  }

  try {
    std::cout << "Calling...\n";

    proxy->call_sync("Method");

    std::cout << "It works!\n";
  }
  catch(const Glib::Error& error) {
    std::cerr << "Got an error: '" << error.what() << "'." << std::endl;
  }

  // Connect an idle callback to the main loop to quit when the main loop is
  // idle now that the method call is finished.
  Glib::signal_idle().connect(sigc::ptr_fun(&on_main_loop_idle));
}

int client_main() {    
  loop = Glib::MainLoop::create();

  auto connection =
    Gio::DBus::Connection::get_sync(Gio::DBus::BUS_TYPE_SESSION);

  if(!connection) {
    std::cerr << "The user's session bus is not available." << std::endl;
    return 1;
  }

  // Create the proxy to the bus asynchronously.
  Gio::DBus::Proxy::create(connection, "org.glibmm.DBusExample",
    "/org/glibmm/DBusExample", "org.glibmm.DBusExample",
    sigc::ptr_fun(&on_dbus_proxy_available));

  loop->run();

  return EXIT_SUCCESS;
}

我编译测试g++ -O2 -std=c++0x main.cc server.cc client.cc -o test $(pkg-config --cflags --libs giomm-2.4)并运行:

./test
on_bus_acquired
Calling...
<it hangs>

但是,当我更改 main.cc 时:

    #include <giomm.h>

    int server_main();
    int client_main();

    int main() {
      Gio::init();
      auto childid = fork();
      if (childid == 0) {
        server_main();
      } else {
        sleep(1);
        client_main();
      }
    }

我得到:

./test
on_bus_acquired
Calling...
Method was called
It works!

所以 call_sync() 成功返回。

我试图从服务器和客户端排除循环,并使用单线程 main.cc:

#include <giomm.h>
#include <thread>

int server_main();
int client_main();

int main() {
    Gio::init();
    server_main();
    client_main();
    auto loop = Glib::MainLoop::create();
    loop->run();
}

没有什么帮助。问题是,我做错了什么?我想在一个进程中使用我的 d-bus 服务器和客户端。

4

1 回答 1

0

我想通了,诀窍是执行

Glib::VariantContainerBase result;
invocation->return_value(result);

在 on_method_call 结束时。

于 2012-09-05T11:41:15.953 回答