Qt程序设计中遇到的一些问题总结-dbus篇

Qt程序设计中遇到的一些问题总结-dbus篇,第1张

这段时间完成了一个Qt程序,并且已经发布,在这里记录下自己在整个设计中遇到的一些坑。关于qtbbus我这里主要写一些systembus方面的一些问题。通过AddBus一个简单的类来描述整个实现过程。在qt中访问dbus,需要在*.pro文件中添加<code>CONFIG += qdbus</code>

服务端非常简单,它只有一个函数实现返回两个参数之和的功能。

<code>#include <QObject>

class AddBus : public QObject

{

Q_OBJECT

public:

explicit AddBus(QObject *parent = 0)

~AddBus()

public Q_SLOTS:

int add(int a, int b)

}</code>

实现完成整个基本功能之后需源差要在qdbuscpp2xml这个软件的帮助下把接口导出称为xml文件。

<code>qdbuscpp2xml addbus.h -o addbus.xml</code>

一般来说生成的xml中关于<code><interface name="local.qdbuscpp2xml.AddBus"></code>这一项的定义都不是非常符合我们的吵裂模要求,需要重新填写。这里我修改为<code><interface name="com.example.addbus.manager"></code>

然后通过qdbusxml2cpp命令生成适配器类

<code>qdbusxml2cpp addbus.xml -a addbus_adaptor</code>

把生成的addbus_adaptor类导入pro中。编辑main.cpp文件

<code>#include "addbus.h"

#include "addbus_adaptor.h"

#include <QApplication>

#include <QCoreApplication>

int main(int argc, char *argv[])

{

QApplication app(argc, argv)

AddBus *add = new AddBus()

new ManagerAdaptor(add)

QDBusConnection conn = QDBusConnection::systemBus()

if (!conn.registerService("com.example.addbus"))

{

qDebug() <<conn.lastError().message()

}

conn.registerObject("/", add)

return app.exec()

}</code>

完成main文件之后,我们就可以编译运行整个程序了,但是我们第一次运行这个程序时,会有一些问题

<code>

sudo ./bus-daemon

"Connection ":1.181" is not allowed to own the service "com.example.addbus" due to security policies in the configuration file" </code>这是说我们刚才注册的com.example.addbus没有在dbus的配置文件中,所以运行不了。这就要涉及到/etc/dbus-1/system.d/目录了,这个目录下面存放了所有systembus的配置文件,我们可以使用其中的文件作为参考来配升缓置我们的配置文件。

<code>

vim com.example.addbus.conf

<!DOCTYPE busconfig PUBLIC

"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"" http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd ">

<busconfig>

<policy user="root">

<allow own="com.example.addbus"/>

</policy>

<policy context="default">

<allow send_destination="com.example.addbus"

send_interface="com.example.addbus.manager"/>

<allow send_destination="com.example.addbus"

send_interface="org.freedesktop.DBus.Introspectable"/>

</policy>

</busconfig>

</code>

拷贝com.example.addbus.conf文件至/etc/dbus-1/system.d/目录下面。通过上面的命令就可以运行dbus-damon程序了,然后使用d-feet工具尝试访问com.example.add总线,并尝试执行add *** 作。

客户端简单描述如何初始化一个systembus和调用server端提供的接口

<code>

m_interface = new ComExampleAddbusManagerInterface("com.example.addbus", "/",

QDBusConnection::systemBus(), this)

if (!m_interface->isValid())

{

qDebug() <<m_interface->lastError().message()

}

m_sum = m_interface->add(m_a, m_b)

</code>

一般来说dbus提供了自动拉起server的功能,这时候需要我们配置一个service服务。这个配置文件需要放在/usr/share/dbus-1/system-services/目录下面。<code>

vim com.example.addbus.service

[D-BUS Service]

Name=com.example.addbus

Exec=/home/crystal/workspace/build-systembus-Desktop-Debug/bus-daemon/bus-daemon

User=root</code>

这时候我们还是拉不起服务,如果我们手动启动后台服务,则整个程序还是可以正常运转的。

这是因为我们的后台服务采用了QApplication启动的,如果我们换成QCoreApplication则可以正常拉启后台服务。

在嵌入式系统中使用dbus主要有两个方面的用途:

1:进程间通信

2:实现厅野client/server模式;

2也是1的具体表现形式;

包括dbus自带的例子,都是采用dbus对数据的封装,实现client/server模式的,

缺点有二:

1 一个API要定义一个xml接口描述

2 数据封装非常复杂,非常不利于以后接口的扩展;

为了客服上面的缺点,提高可扩展性和效率,可以这样做衡塌:

如果一个应用分为client,server两端的话,要高效率的实现client/server之间

的通信,可以采用如下方式:

第一步:定义一个通用的API xml 接口描述,暂命令为dbus_general.xml

<?xml version="1.0" encoding="UTF-8" ?>

<node name="/org/freedesktop/DBus/General_api">

<interface name="org.freedesktop.DBus.general_api">

<method name="client_request">

<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="__client_request_cb"/>

<arg type="i" name="action_id" direction="in" /> //这个地方就是不同API的ID

<arg type="i" name="input_int" direction="in" /> //这个参数可以用,也可以不用

<arg type="ay" name="input_garray" direction="in" /> //这个Garray用来从client传咐伏圆递数据,包括复杂的数据结构到server

<arg type="i" name="outut_int" direction="out" /> //这个可以用,也可以不用

<arg type="ay" name="output_garray" direction="out" />//这个Garray用来从server侧传回数据到client侧

<arg type="i" name="result" direction="out" />

</method>

</interface>

</node>

大家知道:在dbus文档中有这么的描述,

ay | Array of bytes | DBUS_TYPE_G_BYTE_ARRAY | GArray * |g_array_free

大家都不常用字节数组(GArray),大家常用的是integar,string等;

这个通用的模板关键之处就是这个Garray, Garray本身是个容器,这个

容器里面可以装任何东西。

我们就是利用这个GArray来实现client与server之间数据的传递,无论想传递

什么要的数据;

第二步:用dbus的工具函数生成stub/proxy头文件,这一步写到Makefile脚本中,以后不用修改了;

dbus-binding-tool --mode=glib-server --prefix=your_module_name dbus_general.xml >general_stub.h

dbus-binding-tool --mode=glib-client --prefix=your_module_name dbus_general.xml >general_proxy.h

生成的头文件,大家一般不要动它们,直接使用就可以了;

general_proxy.h:

.....

client_request (DBusGProxy *proxy, const gint IN_action_id, const gint IN_input_int, const GArray* IN_input_garray, gint* OUT_output_int, GArray** OUT_output_garray, gint* OUT_result, GError **error)

{

return dbus_g_proxy_call (proxy, "request", error, G_TYPE_INT, IN_action_id, G_TYPE_INT, IN_input_int, dbus_g_type_get_collection ("GArray", G_TYPE_UCHAR), IN_input_garray, G_TYPE_INVALID, G_TYPE_INT, OUT_output_int, dbus_g_type_get_collection ("GArray", G_TYPE_UCHAR), OUT_output_garray, G_TYPE_INT, OUT_result, G_TYPE_INVALID)

}

.....

general_stub.h:

.....

#include <dbus/dbus-glib.h>

static const DBusGMethodInfo dbus_glib_your_module_name_methods[] = {

{ (GCallback) __client_request_cb, dbus_glib_marshal_your_module_name_BOOLEAN__INT_INT_BOXED_POINTER_POINTER_POINTER_POINTER, 0 },

}

const DBusGObjectInfo dbus_glib_your_module_name_object_info = {

0,

dbus_glib_your_module_name_methods,

1,

"org.freedesktop.DBus.general_api/0client_request/0S/0action_id/0I/0i/0input_int/0I/0i/0input_garray/0I/0ay/0output_int/0O/0F/0N/0i/0output_garray/0O/0F/0N/0ay/0result/0O/0F/0N/0i/0/0/0",

"/0",

"/0"

}

......

第三步:实现client侧,主要是直接调用general_proxy.h的接口函数client_request(),用GArray传入你的数组(可以携带任何你自己定义的数据结构)

gboolean proxy_func1 (void)

{

int api_id = 0 //这个在不同的proxy_func里面可以有不同的值,主要是区分函数作用

GArray* in_array = NULL

GArray* out_array = NULL//在这里不用分配内存,放在server侧做内存分配

in_array = g_array_new(FALSE, FALSE, sizeof(guint8))

if (!in_array)

return FALSE

//把你自己的数据封装到in_array中,假设你的数据结构是your_strcut_t

your_struct_t my_own_data

//fill my_own_data

...

//放到in_array中,这很关键

g_array_append_vals(in_array, my_own_data, sizeof(your_strcut_t))

//调用general_proxy.h中的dbus接口

client_request(dbus_proxy, api_id, in_array, &out_array, .....)//通过dbus把数据从到server侧,server侧如何处理,看第四步;

//当sever返回数据后,从out_array中取出来就可以了

your_strcut_t* g_array_data = (your_strcut_t*)out_array->data

.....

//free

if (in_array)

g_free (in_array)

if (out_array)

g_free (out_array)

....

}

第四步:实现Server侧,主要是实现general_stub.h中的函数__client_request_cb()

//这个函数的参数很长,除了第一个参数是server对象外,其余的参数可以直接从

general_proxy.h对应的接口参数拷贝过来;应该这个函数和proxy的接口是一对!

gboolean

__client_request_cb (ServerObject *server_object, const gint IN_action_id, const gint IN_input_int, const GArray* IN_input_garray, gint* OUT_output_int, GArray** OUT_output_garray, gint* OUT_result, GError **error)

{

*OUT_output_garray = g_array_new(FALSE, FALSE, sizeof(guint8))//在client侧没有分配内存,server这里一定要分配

//卸下client侧传递过来的数据

your_strcut_t ×p_data= (your_strcut_t *)&g_array_index(input_garray,your_strcut_t, 0)

//对卸下的数据进行处理,看你的程序做什么功能了:)

.....

.....

//如果要传回数据到client侧,假设处理过的数据为:your_strcut_t dealed_with_data

g_array_append_vals(*output_garray, &dealed_with_data, sizeof(your_strcut_t))

return TRUE//一定要返回TRUE,否则client侧收不到数据的;

}

上述通用步骤中,1,2在今后的扩展中,是不要要改的,尤其是第一步,dbus的xml接口描述非常

麻烦;如果为每个API自己去定义xml接口描述,搞不好,client和server之间不通;而且,一段时间

后,不看dbus的文档,就会忘记如何写其xml接口;所以做个通用的xml接口描述很省事;

3,4是client/server侧的各自实现,结构是钉死的,不用改多少;一个函数如此,N个函数也是这样;

如果你有30个函数,要分别实现它们吗?不必要,只要给各自的函数定义其ID就行;

在client/server侧的函数里面搞个switch-case结构就分开了;

架构定好了,传递数据也非常方便,比dbus自己的dbus_g_type_struct_set效率高的多,目前开源软件

多用dbus_g_type_struct_set,效率很低,对于传递批量数据,效率很低;

如果大家对于如何提高dbus传递消息/数据的效率,有什么更好的看法,欢迎交流。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/8189860.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-14
下一篇 2023-04-14

发表评论

登录后才能评论

评论列表(0条)

保存