2012-09-05 2 views
2

Когда я создаю сервер D-Bus (через g_bus_own_name()) и клиент к нему (используя g_dbus_proxy_new()) в том же процессе, а затем вызывается g_dbus_proxy_call_sync(), он никогда не возвращается , Однако, если сервер и клиент находятся в отдельных процессах, все в порядке.DBus клиент и сервер в том же процессе

Следующий код иллюстрирует мою проблему (я использую 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; 
} 

файл .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 в одном процессе.

ответ

0

Я понял это, хитрость заключается в том, чтобы выполнить

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

в конце on_method_call.

+0

Я не думаю, что ваше решение правильно. Кажется, вы используете два цикла run() в одном основном процессе каждый внутри процесса server_main() и client_main(). Первый цикл цикла() на сервере блокирует все ваши процессы. Я не думаю, что функция client_main() будет достигнута. У вас есть несколько отчетов журнала? – enthusiasticgeek

Смежные вопросы