基本概念 下(C API 级别的使用观点)
扫描二维码
随时随地手机看文章
通信数据的设置和获取
前篇主要是有讲一些相对高层的概念,比如 object,interface,method 之类的,对于这些“C 本来没有的东西”,如何在 DBus 中表现的确实很让我迷惑了一阵。但通信数据的发送可能比前面那些名称好理解得多。因为这些概念都是很本来就是底层的,很 C 的。
DBus 提供了一个 DBusMessageIter 的类型,使用这个类型的变量,我们就可以向 DBusMessage 中很容易地加入数据,也可以很容易地从中取出数据。
DBusMessage* msg;DBusMessageIter args; // msg... dbus_message_iter_init_append(msg, &args);dbus_uint32_t my_data = 10;if(!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &my_data)) { printf("Out of memoryn"); return RES_FAILED;} dbus_connection_flush(conn);dbus_message_unref(msg);
第 2 行的代码声明了一个 DBusMessageIter 的对象 args,第 6 行的代码处,对 args 进行初始化,这可以让一个 DBusMessageIter 对象与对应的 DBusMessage 关联起来,后面再对 DBusMessageIter的时候(设置或者取得数据),就是对相应的 DBusMessage 进行处理。然后使用第8行的函数,将一个 uint32 的数据 my_data 追加到 msg 中了。如果还要追加新的参数的话,只需要继续调用该函数,并传入适当的参数就可以了。
dbus_bool_t dbus_message_iter_append_basic(DBusMessageIter * iter, inttype, const void * value )
这个函数可以用来向 DBusMessageIter 中追加一些“基本类型”(basic)的数据,所谓基本类型的数据,在 DBus 中是这么定义的:
Conventional Name
Encoding
Alignment
BYTE
A single 8-bit byte.
1
BOOLEAN
As for UINT32
, but only 0 and 1 are valid values.
4
INT16
16-bit signed integer in the message's byte order.
2
UINT16
16-bit unsigned integer in the message's byte order.
2
INT32
32-bit signed integer in the message's byte order.
4
UINT32
32-bit unsigned integer in the message's byte order.
4
INT64
64-bit signed integer in the message's byte order.
8
UINT64
64-bit unsigned integer in the message's byte order.
8
DOUBLE
64-bit IEEE 754 double in the message's byte order.
8
STRING
A UINT32
indicating the string's length in bytes excluding its terminating nul, followed by non-nul string data
of the given length, followed by a terminating nul byte.
4
(for the length)
OBJECT_PATH
Exactly the same as STRING
except the content must be a valid object path (see below).
4
(for the length)
(参考 DBus 的在线 API 的 Marshaling (Wire Format) 一节)
有 basic type,当然也就有更复杂的不是 basic 的类型,但这和基本概念的关系不大,在这篇文章中就不多介绍了。(请参考我其它的 DBus 博文)
到现在为止,我已经知道如何把数据入到一个 DBusMessage 中了,那么,如何从一个 DBusMessage 中取出数据呢?比如,我在 A 进程使用上面的代码把 my_data 加到 DBusMessage 中了,现在 B 进程取到了 DBusMessage,如何把数据取出来呢?
DBusMessage* msg;DBusMessageIter args; // get a DBusMessage from process A if(!dbus_message_iter_init(msg, &args)) { printf("dbus_message_iter_init error, msg has no arguments!n");}else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args)){ printf("not a uint 32 type !n");}else { dbus_uint32_t my_age = 0; dbus_message_iter_get_basic(&args, &my_age); printf("Got signal with value %dn", my_age);}
很简单,一样的先使用 dbus_messge_iter_init 先把 DBusMessage 对象和从 DBus 总线中取到的 msg 关联起来。这样,使用第 9 行的函数先取得第一个通信数据中第一个参数的类型,如果类型无误的话可以进而使用第 14 行的函数取得参数值本身。
这样,一个简单的数据如何入到 DBusMessage 中,又如何从 DBusMessage 中取出来就明白了。那么如何将 DBusMessage 在进程之间传递呢?
消息的发送和获取
消息的发送其实比较简单,当进程 A 准备申请好一个 DBusMessage对象,设置好它的“类型”(就是各种名字),放好需要通信的数据,之后,使用下面的代码就可以将数据发送到总线上:
dbus_uint32_t serial = 0; if(!dbus_connection_send(conn, msg, &serial)) { printf("Out of memory"); return RES_FAILED;}dbus_connection_flush(conn);
这很简单,只是 dbus_connection_flush 这个函数有点突兀,它的作用是“Blocks until the outgoing message queue is empty.”,可以简单地理解为调用这个函数可以使用得发送进程一直等消息发送完了才能继续运行。
接受方的代码也很简单:
dbus_connection_read_write(conn, 0);msg = dbus_connection_pop_message(conn); if(NULL == msg) { sleep(1); continue;}
使用 1 和 2 行的代码就可以取出发送到本进程的消息,之后就可以使用 msg (如果 msg 不是 NULL 的话)来获取通信数据了。
到这里,基本概念就有了。后面,应该对 DBus 的细节再深入的探索。
Sample 代码:
发送方进程(my_client):
My_Client.cpp #include