g_bus_own_name连接总线失败

最近采用gdbus-codegen写了一组服务端和客户端,主要实现的功能是用服务端给客户端发送信号,但是在服务端中发现一个问题。

 在虚拟机中测试正常,信号能够正常发送,但是在车机上运行时会一直阻塞。仔细梳理了一下代码逻辑后发现是阻塞在了sem_wait处,这里信号量的作用是等待on_bus_acquired函数调用(也就是连接上dbus总线后)完成后再发送信号。可是就是不能调用on_bus_acquired函数,试了很多方法,最后发现是g_bus_own_name函数形式少了一个参数,原来的代码是:

1
2
3
4
5
6
7
owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, //bus_type
"com.hangsheng.UPDATE.InformServer", //bus_name
G_BUS_NAME_OWNER_FLAGS_NONE, //flag
on_bus_acquired, //注册输出对象的回调函数
NULL,
NULL,
NULL);

对比官网的参数原型,发现原代码中只有七个参数,而官方用法中有八个参数:

1
2
3
4
5
6
7
guint g_bus_own_name (GBusType bus_type, const gchar *name,
GBusNameOwnerFlags flags,
GBusAcquiredCallback bus_acquired_handler,
GBusNameAcquiredCallback name_acquired_handler,
GBusNameLostCallback name_lost_handler,
gpointer user_data,
GDestroyNotify user_data_free_func);

再仔细对比,发现少了name_lost_handler这个回调函数,根据官网的说明,调用g_bus_own_name函数有三个结果:

You are guaranteed that one of the name_acquired_handler and name_lost_handler callbacks will be invoked after calling this function there are three possible cases:

  • name_lost_handler with a NULL connection (if a connection to the bus can t be made).
  • bus_acquired_handler then name_lost_handler (if the name can t be obtained)
  • bus_acquired_handler then name_acquired_handler (if the name was obtained).

于是对照官网重新写了g_bus_own_name函数,结果发现是第一种情况,直接调用了name_lost_handler 这个函数,也就是没有连接上,所以也就不能够回调bus_acquired_handler函数,所以一直在阻塞等待该函数完成时会陷入死循环。

阻塞的原因找到后,就要继续查找为什么会注册失败,最后发现是因为没有设置dbus的总线地址,导致连接失败。无论是gdbus,qdbus,还是commonapi等都是基于dbus的高级语言封装,他们在通信时都需要底层的dbus先准备好。而dbus在使用中需要设置bus address,这里可以设置一个环境变量:

1
export DBUS_SESSION_BUS_ADDRESS= unix:path=/run/dbus/session_bus_help

再次测试代码,问题解决!

ps:

而且通过对官方接口的阅读,发现可以将发送信号操作放在name_acquired_handler这个回调函数里面,因为这个函数会在bus_acquired_handler函数完成后调用,这时候发送信号不会因为还没有连接上dbus总线而发送失败。


g_bus_own_name连接总线失败
https://www.shangyexin.com/2017/01/11/g-bus-own-name/
作者
Yasin
发布于
2017年1月11日
许可协议