QDBus与gdbus的数据传递详解
在Linux平台的进程间通信多了⼀个dbus技术,应⽤还是⾮常⼴的,其中有⼀个应⽤模式是采⽤gdbus实现相关业务逻辑,采⽤QtService 调⽤qdbus暴露出服务给客户使⽤。这种模式还是⾮常便捷的。不过QDBus和gdbus相关资料还请⾃⾏查。这⾥只是针对他们的数据传递(函数的参数)进⾏详解。
1,框架的建⽴
⾸先我们需要根据业务需要建议⼀个xml⽂件l,描述interface以及包含的函数等信息,⽐如:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="introspect.xsl"?>
<node xmlns:xsi="/2001/XMLSchema-instance" name="/org/alibaba/kenton" xsi:noNamespaceSchemaLocation="introspect.xsd">
<interface name="org.alibaba.kenton.hello">
<version>1.0.0</version>
<doc>
<line>This is a test interface</line>
</doc>
<method name="GetVersion">
<doc>
<line>GetVersion = This method returns the API version implemented by the server application</line>
</doc>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="SVersion"/>
<arg name="version" type="(qqqs)" direction="out">
<doc>
<line>version = struct(major,minor,micro,date)</line>
<line>major = major</line>
<line>minor = minor</line>
<line>micro = micro</line>
<line>date = release date</line>
</doc>
</arg>
</method>
</interface>
</node>
a,QDBus端
这⾥,我们只是随便弄个interface以及⼀个函数名为GetVersion。有这个XML我们就可以利⽤⼯具qdbusxml2cpp创建对应的cpp⽂件。l -i hello_type.h HelloInterface
这条命令⽤于创建qdbus对应的接⼝,HelloInterface.cpp/.h,供QtService接⼝调⽤。其中-i hello_type.h表明创建出来的HelloInterface.h需要include hello_type.h。不过当前⽬前是不需要这个头⽂件的。只需要在实际项⽬⽬录底下有这个⽂件即可。那问题来了,我们要这个⽂件⼲嘛?因为在xml⽂件,我们GetVersion的参数是个结构体,对于这种复杂类型(包括结构体,类,QList,QMap 等)我们需要在⼀个头⽂件⾥定义。同时还需要实现相应的流操作符,这⾥只列出头⽂件的内容:
struct SVersion
{
quint16 mMajor;
quint16 mMinor;
quint16 mMicro;
QString mDate;
SVersion() : mMajor(0), mMinor(0), mMicro(0), mDate("")
{
}
bool operator==(const SVersion &other) const
{
return (mMajor == other.mMajor) && (mMinor == other.mMinor) && (mMicro == other.mMicro) && (mDate == other.mDate);
}
};
QDBusArgument& operator<<(QDBusArgument& arg, const SVersion& version);
const QDBusArgument& operator>>(const QDBusArgument& arg, SVersion& version);
同时需要在使⽤HelloInterface之前注册为qDBus的元类型:qDBusRegisterMetaType<navigationcore::session::SVersion>();
有了这些QDBus端,算是⼤功告成了。
b,gdbus端
同样,我们需要使⽤gdbusxml2cpp创建gdbus相关c⽂件,(这⾥不列出创建出来的⽂件了):
gdbus-codegen --generate-c-code l
之后,我们需要创建⼀个具体显⽰相关业务的c⽂件,其中内容有:
void connectHelloInterface(OrgAlibabaKentonHello* helloServerObject,GDBusConnection *connection)
{
GError* err = NULL;
/*接⼝的连接*/
g_signal_connect(sessionServerObject, "handle_get_version", G_CALLBACK(&gdbus_get_version), NULL);
/*接⼝的输出*/
if(true != g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(sessionServerObject), connection, PHELLOSERVER_KENTON_DBUS_OBJEC {
LOG("export interface failed");
}
else
{
LOG("export interface success");
namespace是干嘛的}
}
其中GetVersion对应的具体业务逻辑的实现如下:
void gdbus_get_version (
OrgAlibabaKentonHello *object,
GDBusMethodInvocation *invocation)
{
LOG_DEBUG(CTX_ID_GUD, "#FI#: gdbus_get_version");
GVariant * version;
GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("(qqqs)"));
g_variant_builder_add(builder, "q", 1);
g_variant_builder_add(builder, "q", 1);
g_variant_builder_add(builder, "q", 0);
g_variant_builder_add(builder, "s", "hello");
version = g_variant_builder_end(builder);
org_alibaba_kenton_hello_complete_get_version(object, invocation, version);
}
这⾥我们通过glib函数g_variant_builder_new创建⼀个和xml⾥参数类型⼀致的variant type:
G_VARIANT_TYPE("(qqqs)") 然后添加相应的值。
⾄此,⼤概的框架就都有了。让我们回到本问的核⼼,各种数据传递。
2,数据传递详解
b,基本数据类型
在xml⽂件⾥指定glib对应的gvariant数据类型,具体查看上⾯的数据类型对应表。
在QDBus端,qdbusxml2cpp已经创建出c/c++对应的数据类型,可直接使⽤。
c,结构体
在xml⽂件⾥,就是上⾯的例⼦。我们需要在xml⾥指定(qqqs),由⼀个括号包围相应数据类型
<arg name="version" type="(qqqs)" direction="out">
在QDbus端,我们需要有个头⽂件,头⽂件⾥声明⼀个对应数据类型的结构体,同时要实现对应的流操作运算符,参考上⾯的例⼦,这⾥不再说明。
在gdbus端,我们需要把数据传回给QDBus端,如下:
GVariant * version;
GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("(qqqs)"));
g_variant_builder_add(builder, "q", 1);
g_variant_builder_add(builder, "q", 1);
g_variant_builder_add(builder, "q", 0);
g_variant_builder_add(builder, "s", "hello");
version = g_variant_builder_end(builder);
org_alibaba_kenton_hello_complete_get_version(object, invocation, version);
d,QList
在xml⽂件⾥,QList对应到glib⾥是a(q),就是⼀个数组,其中数据类型可以是任意。
在QDBus端,我们可以typedef QList<quint16> QShortList; 把ShortList放在xml⽂件函数参数的annotation中,如下:
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QShortList"/>
在glib端,对应的代码:
GVariant * version;
GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("a(q)"));
g_variant_builder_add(builder, "q", 1);
g_variant_builder_add(builder, "q", 2);
g_variant_builder_add(builder, "q", 3);
version = g_variant_builder_end(builder);
org_alibaba_kenton_hello_complete_get_xxxx(object, invocation, version);
e,QMap
在xml⽂件⾥,QList对应到glib⾥是a{qv},就是⼀个字典数组。
在QDBus端,我们可以typedef QMap<quint16, QDBusVariant> QShortMap; 把ShortList放在xml⽂件函数参数的annotation中,如下:
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QShortMap"/>
<span > </span>GVariant* map_item;
GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("a{qv}"));
g_variant_builder_add(builder, "{qv}", 1, g_variant_new_uint16(11));
<span > </span>g_variant_builder_add(builder, "{qv}", 2, g_variant_new_uint16(22));
map_item = g_variant_builder_end(builder);
g_variant_builder_unref(builder);
f,QList<QMap<uint16, QDBusVariant> >
QList和QMap我们都已经会那,那QList的元素是个QMap呢,其实也⼀样,variant type 是“aa{qv}",只是在添加数据的时候需要注意⼀下。
这⾥就只是列出gdbus中的代码:
GVariant* points_list;
GVariantBuilder* points_builder = g_variant_builder_new(G_VARIANT_TYPE("aa{qv}"));
for (int i = 0; i < nJnyPointNum; i++)
{
GVariant* points_item;
GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("a{qv}"));
g_variant_builder_add(builder, "{qv}", 1, g_variant_new_uint16(11));
g_variant_builder_add(builder, "{qv}", 2, g_variant_new_double(22.22));
points_item = g_variant_builder_end(builder);
g_variant_builder_unref(builder);
<span >g_variant_builder_add_value(points_builder, points_item);// 关键是这⾏,需要调⽤add_value来添加⼀个QMap</span> }
points_list = g_variant_builder_end(way_points_builder);
g_variant_builder_unref(points_builder);
g,结构体
对于结构体中只包含基本数据类型,可以批量添加,如下:
g_variant_builder_add(pvBuilder, "(uiqnnb)",
u32Param,
n32Param,
u16Param,
n16Param,
bParam);
h,结构体中包含复杂数据类型,⽐如QMap,如下:
对于结构体中包含复杂数据类型,则需先构造出复杂数据类型,然后再添加各个数据;同时通过
g_variant_builder_add_value
来添加复杂数据类型。
GVariant* pvMapItem = ...
GVariantBuilder* pvBuilder = g_variant_builder_new(G_VARIANT_TYPE("(uiqa{qv})"));
g_variant_builder_add(pvBuilder, "u", u32);
g_variant_builder_add(pvBuilder, "i", n32);
g_variant_builder_add(pvBuilder, "q", u16);
g_variant_builder_add_value(pvBuilder, pvMapItem);
有了⽀持以上数据类型,我想基本是够⽤了。这⾥没有想太详细介绍所有涉及的知识点,但是有了这些知识就有助于实际开发当中的⽤例。否则⼀开始⽤还是⽐较不⽅便的。
有空再补⼀下更加详细的信息。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论