QDBus与gdbus的数据传递详解

来源:互联网 发布:asp.net 明细数据输入 编辑:程序博客网 时间:2024/06/08 10:02

QDBus与gdbus的数据传递详解

感谢大神分享,原文链接:http://blog.csdn.net/kentonwu/article/details/47281101

在Linux平台的进程间通信多了一个dbus技术,应用还是非常广的,其中有一个应用模式是采用gdbus实现相关业务逻辑,采用QtService调用qdbus暴露出服务给客户使用。这种模式还是非常便捷的。不过QDBus和gdbus相关资料还请自行查找。这里只是针对他们的数据传递(函数的参数)进行详解。

1,框架的建立

首先我们需要根据业务需要建议一个xml文件hello.xml,描述interface以及包含的函数等信息,比如:

[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <?xml-stylesheet type="text/xsl" href="introspect.xsl"?>  
  3. <node xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="/org/alibaba/kenton" xsi:noNamespaceSchemaLocation="introspect.xsd">  
  4.   <interface name="org.alibaba.kenton.hello">  
  5.     <version>1.0.0</version>  
  6.     <doc>  
  7.       <line>This is a test interface</line>  
  8.     </doc>  
  9.     <method name="GetVersion">  
  10.       <doc>  
  11.         <line>GetVersion = This method returns the API version implemented by the server application</line>  
  12.       </doc>  
  13.       <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="SVersion"/>  
  14.       <arg name="version" type="(qqqs)" direction="out">  
  15.         <doc>  
  16.           <line>version = struct(major,minor,micro,date)</line>  
  17.           <line>major = major</line>  
  18.           <line>minor = minor</line>  
  19.           <line>micro = micro</line>  
  20.           <line>date = release date</line>  
  21.         </doc>  
  22.       </arg>  
  23.     </method>  
  24.   </interface>  
  25. </node>  

a,QDBus端

这里,我们只是随便弄个interface以及一个函数名为GetVersion。有这个XML我们就可以利用工具qdbusxml2cpp创建对应的cpp文件。

[plain] view plain copy
  1. qdbusxml2cpp hello.xml -i hello_type.h HelloInterface  

这条命令用于创建qdbus对应的接口,HelloInterface.cpp/.h,供QtService接口调用。其中-i hello_type.h表明创建出来的HelloInterface.h需要include hello_type.h。不过当前目前是不需要这个头文件的。只需要在实际项目目录底下有这个文件即可。那问题来了,我们要这个文件干嘛?因为在xml文件,我们GetVersion的参数是个结构体,对于这种复杂类型(包括结构体,类,QList,QMap等)我们需要在一个头文件里定义。同时还需要实现相应的流操作符,这里只列出头文件的内容:

[cpp] view plain copy
  1. struct SVersion  
  2. {   
  3.   quint16 mMajor;   
  4.   quint16 mMinor;   
  5.   quint16 mMicro;   
  6.   QString mDate;   
  7.   
  8.   
  9.   SVersion() : mMajor(0), mMinor(0), mMicro(0), mDate("")  
  10.   {  
  11.   }  
  12.   bool operator==(const SVersion &other) const  
  13.   {   
  14.     return (mMajor == other.mMajor) && (mMinor == other.mMinor) && (mMicro == other.mMicro) && (mDate == other.mDate);  
  15.   }  
  16. };  
  17.   
  18.   
  19. QDBusArgument& operator<<(QDBusArgument& arg, const SVersion& version);  
  20. const QDBusArgument& operator>>(const QDBusArgument& arg, SVersion& version);  

同时需要在使用HelloInterface之前注册为qDBus的元类型:qDBusRegisterMetaType<navigationcore::session::SVersion>();


有了这些QDBus端,算是大功告成了。

b,gdbus端

同样,我们需要使用gdbusxml2cpp创建gdbus相关c文件,(这里不列出创建出来的文件了):

[plain] view plain copy
  1. gdbus-codegen --generate-c-code gdbusHello hello.xml  


之后,我们需要创建一个具体显示相关业务的c文件,其中内容有:

[cpp] view plain copy
  1. void connectHelloInterface(OrgAlibabaKentonHello* helloServerObject,GDBusConnection *connection)  
  2. {  
  3.     GError* err = NULL;  
  4.   
  5.   
  6.     /*接口的连接*/  
  7.     g_signal_connect(sessionServerObject, "handle_get_version", G_CALLBACK(&gdbus_get_version), NULL);  
  8.   
  9.   
  10.     /*接口的输出*/  
  11.     if(true != g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(sessionServerObject), connection, PHELLOSERVER_KENTON_DBUS_OBJECT_PATH, &err))  
  12.     {  
  13.         LOG("export interface failed");  
  14.     }  
  15.     else  
  16.     {  
  17.         LOG("export interface success");  
  18.     }  
  19. }  
其中GetVersion对应的具体业务逻辑的实现如下:

[cpp] view plain copy
  1. void gdbus_get_version (  
  2.   OrgAlibabaKentonHello *object,  
  3.   GDBusMethodInvocation *invocation)  
  4. {  
  5.     LOG_DEBUG(CTX_ID_GUD, "#FI#: gdbus_get_version");  
  6.   
  7.     GVariant * version;  
  8.     GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("(qqqs)"));  
  9.     g_variant_builder_add(builder, "q", 1);  
  10.     g_variant_builder_add(builder, "q", 1);  
  11.     g_variant_builder_add(builder, "q", 0);  
  12.     g_variant_builder_add(builder, "s""hello");  
  13.     version = g_variant_builder_end(builder);  
  14.   
  15.     org_alibaba_kenton_hello_complete_get_version(object, invocation, version);  
  16. }  

这里我们通过glib函数g_variant_builder_new创建一个和xml里参数类型一致的variant type:

G_VARIANT_TYPE("(qqqs)") 然后添加相应的值。


至此,大概的框架就都有了。让我们回到本问的核心,各种数据传递。

2,数据传递详解

a,glib数据类型,从glib官网https://developer.gnome.org/glib/stable/gvariant-format-strings.html


b,基本数据类型

在xml文件里指定glib对应的gvariant数据类型,具体查看上面的数据类型对应表。

在QDBus端,qdbusxml2cpp已经创建出c/c++对应的数据类型,可直接使用。


c,结构体

在xml文件里,就是上面的例子。我们需要在xml里指定(qqqs),由一个括号包围相应数据类型

<arg name="version" type="(qqqs)" direction="out">

在QDbus端,我们需要有个头文件,头文件里声明一个对应数据类型的结构体,同时要实现对应的流操作运算符,参考上面的例子,这里不再说明。

在gdbus端,我们需要把数据传回给QDBus端,如下:

[cpp] view plain copy
  1. GVariant * version;  
  2. GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("(qqqs)"));  
  3. g_variant_builder_add(builder, "q", 1);  
  4. g_variant_builder_add(builder, "q", 1);  
  5. g_variant_builder_add(builder, "q", 0);  
  6. g_variant_builder_add(builder, "s""hello");  
  7. version = g_variant_builder_end(builder);  
  8.   
  9. 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中,如下:

[html] view plain copy
  1. <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QShortList"/>  
在glib端,对应的代码:

[cpp] view plain copy
  1. GVariant * version;  
  2. GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("a(q)"));  
  3. g_variant_builder_add(builder, "q", 1);  
  4. g_variant_builder_add(builder, "q", 2);  
  5. g_variant_builder_add(builder, "q", 3);  
  6. version = g_variant_builder_end(builder);  
  7.   
  8. 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中,如下:

[html] view plain copy
  1. <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QShortMap"/>  

[cpp] view plain copy
  1. <span style="white-space:pre">    </span>GVariant* map_item;  
  2.         GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("a{qv}"));  
  3.   
  4.         g_variant_builder_add(builder, "{qv}", 1, g_variant_new_uint16(11));  
  5. <span style="white-space:pre">    </span>g_variant_builder_add(builder, "{qv}", 2, g_variant_new_uint16(22));  
  6.   
  7.         map_item = g_variant_builder_end(builder);  
  8.         g_variant_builder_unref(builder);  
f,QList<QMap<uint16, QDBusVariant> >

QList和QMap我们都已经会那,那QList的元素是个QMap呢,其实也一样,variant type 是“aa{qv}",只是在添加数据的时候需要注意一下。

这里就只是列出gdbus中的代码:


[cpp] view plain copy
  1. GVariant* points_list;  
  2. GVariantBuilder* points_builder = g_variant_builder_new(G_VARIANT_TYPE("aa{qv}"));  
  3.   
  4. for (int i = 0; i < nJnyPointNum; i++)  
  5. {  
  6.     GVariant* points_item;  
  7.     GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("a{qv}"));  
  8.   
  9.     g_variant_builder_add(builder, "{qv}", 1, g_variant_new_uint16(11));   
  10.     g_variant_builder_add(builder, "{qv}", 2, g_variant_new_double(22.22));   
  11.   
  12.     points_item = g_variant_builder_end(builder);  
  13.     g_variant_builder_unref(builder);  
  14.     <span style="color:#ff0000;">g_variant_builder_add_value(points_builder, points_item);// 关键是这行,需要调用add_value来添加一个QMap</span>  
  15. }  
  16. points_list = g_variant_builder_end(way_points_builder);  
  17. g_variant_builder_unref(points_builder);  

g,结构体

对于结构体中只包含基本数据类型,可以批量添加,如下:

[cpp] view plain copy
  1. g_variant_builder_add(pvBuilder, "(uiqnnb)",  
  2.                                   u32Param,  
  3.                                   n32Param,  
  4.                                   u16Param,  
  5.                                   n16Param,  
  6.                                   bParam);  

h,结构体中包含复杂数据类型,比如QMap,如下:

对于结构体中包含复杂数据类型,则需先构造出复杂数据类型,然后再添加各个数据;同时通过

[cpp] view plain copy
  1. g_variant_builder_add_value  
[cpp] view plain copy
  1. 来添加复杂数据类型。  

[cpp] view plain copy
  1. GVariant* pvMapItem = ...  
  2. GVariantBuilder* pvBuilder = g_variant_builder_new(G_VARIANT_TYPE("(uiqa{qv})"));  
  3.             g_variant_builder_add(pvBuilder, "u", u32);  
  4.             g_variant_builder_add(pvBuilder, "i", n32);  
  5.             g_variant_builder_add(pvBuilder, "q", u16);  
  6.             g_variant_builder_add_value(pvBuilder, pvMapItem);  

有了支持以上数据类型,我想基本是够用了。这里没有想太详细介绍所有涉及的知识点,但是有了这些知识就有助于实际开发当中的用例。否则一开始用还是比较不方便的。


0 0
原创粉丝点击