QT 4.7 DBUS Binding如何支持自定义数据类型的传输(一)
2011-01-19 18:17
609 查看
对该问题的兴趣,源于之前的一个麻烦问题,如何让QT 4.7 支持DBUS调用中传递"aas(字符串二维数组)“ 数据据类型(详见http://blog.csdn.net/shallon_luo/archive/2011/01/18/6149616.aspx),虽然该问题已经解决,但是只能算了解个配置方法,下面是更深入的了解。
首先是找了一个更深入的学习资料http://laurii.info/articles/2007/03/22/dbus-and-qt-programming 下文的学习资料的代码例子从该链接可以下载。
这里先讨论,QT DBUS Binding用在通信的服务器端的情形。
第一步,首先看看这个示例DBUS接口的描述XML
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/com/trollech/examples/car">
<interface name="com.trolltech.Examples.CarInterface">
<method name="accelerate"/>
<method name="decelerate"/>
<method name="turnLeft"/>
<method name="turnRight"/>
<method name="structer">
<annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="MyStruct"/>
<arg type="(sxs)" direction="out"/>
<arg type="x" direction="out"/>
</method>
<signal name="crashed"/>
</interface>
</node>
可以注意到:1.这个红色字体函数声明中,有两个返回参数。 2.第一个返回参数被声明成了自定义的类型MyStruct .
第二步,看看QT DBUS Binding工具 qdbusxml2cpp是怎么翻译这个XML文件
运行 qdbusxml2cpp -i mystruct.h -c CarAdaptor -a car_adaptor_p.h:car_adaptor.cpp car.xml
注意,这是服务器端运行的命令,客户端运行另一命令(qdbusxml2cpp -c CarInterface -p car_interface_p.h:car_interface.cpp -i mystruct.h car.xml) 这里不再描述。
第三步,看看生成的car_adaptor_p.h:car_adaptor.cpp文件,能发现下列问题
1. 生成了CarAdaptor,该类是QDBusAbstractAdaptor的一个子类。QDBusAbstractAdaptor是QT对象与DBUS绑定的桥梁。其基本用法是:
a: QDBusAbstractAdaptor其子类是一个普通 QObject对象的轻量封装对象,在此处QObject对象是提供DBUS服务的业务对象。在代码中,这个QObject对象称为“QDBusAbstractAdaptor的parent对象” ,在本例子中,这个业务对象是Car对象。
b:通过QDBusConnection::registerObject方法注册parent对象。(见第四步的main函数的逻辑部分)
2.CarAdaptor通过Q_CLASSINFO将DBUS访问的接口信息插入QT元数据描述中。
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "com.trolltech.Examples.CarInterface")
Q_CLASSINFO("D-Bus Introspection", ""
" <interface name=/"com.trolltech.Examples.CarInterface/" >/n"
" <method name=/"accelerate/" />/n"
" <method name=/"decelerate/" />/n"
" <method name=/"turnLeft/" />/n"
" <method name=/"turnRight/" />/n"
" <method name=/"structer/" >/n"
" <annotation value=/"MyStruct/" name=/"com.trolltech.QtDBus.QtTypeName.Out0/" />/n"
" <arg direction=/"out/" type=/"(sxs)/" />/n"
" <arg direction=/"out/" type=/"x/" />/n"
" </method>/n"
" <signal name=/"crashed/" />/n"
" </interface>/n"
"")
这里很难能透彻理解,可以运行qmake ,看看其生成的moc_car_adaptor_p.cpp文件,看看Q_CLASSINFO插入DBUS值对真正的代码是什么。
3.发现XML定义的structer函数原型被映射成:
其规律是第一个返回的参数被定义成返回值,第二个返回的参数被映射成引用的参数。
第四步,看看MyStruct 的自定义
class MyStruct {
public:
QString element1;
qlonglong element2;
QString element3;
};
Q_DECLARE_METATYPE(MyStruct)
inline void registerCommTypes() {
qDBusRegisterMetaType<MyStruct>();
}
QDBusArgument &operator<<(QDBusArgument &argument, const MyStruct &mystruct);
const QDBusArgument &operator>>(const QDBusArgument &argument,
MyStruct &mystruct);
1.定义MyStruct 的结构
2.声明MyStruct的元数据类型
3.向QT Dbus Binding注册MyStruct元数据类型
4.实现序列化与反序列化的函数 << | >> 用于从DBUS文本消息到MyStruct的双向转换。
5.Main 函数,主要逻辑如下:
new CarAdaptor(car);
QDBusConnection connection = QDBusConnection::sessionBus();
connection.registerObject("/Car", car);
connection.registerService("com.trolltech.CarExample");
6.调用流程日志
1.DBUS消息如下:
method call sender=:1.386 -> dest=:1.384 serial=166 path=/Car; interface=com.trolltech.Examples.CarInterface; member=structer
method return sender=:1.384 -> dest=:1.386 reply_serial=166
struct {
string "unu"
int64 2
string "trei"
}
int64 12345
2.程序调用日志显示调用路径
QDBusArgument &operator<<(mystruct.cpp)
Calling structer (carAdaptor.cpp)
Calling structer (car.cpp)
QDBusArgument &operator<<(mystruct.cpp)
从日志可以分析,第一条DBUS消息发出后,首先进入的是carAdaptor.cpp的structer函数,然后进入其业务对象Car的structer函数。最后运行结果返回,structer返回的MyStrct对象是序列化成DBUS消息被发送给客户端。
这里不解的地方是:为何QDBusArgument &operator<<被调用了两次?
分析:
当DBUS请求发送过来时,QT DBUS Binding应该是通过carAdaptor.cpp注册的DBUS 元数据信息找到了CarAdaptor对象,并且触发相关的方法,CarAdaptor对象将请求转发给其parent对象(Car),运行完成后由QT DBUS框架自动进行序列化成DBUS消息返回。
首先是找了一个更深入的学习资料http://laurii.info/articles/2007/03/22/dbus-and-qt-programming 下文的学习资料的代码例子从该链接可以下载。
这里先讨论,QT DBUS Binding用在通信的服务器端的情形。
第一步,首先看看这个示例DBUS接口的描述XML
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/com/trollech/examples/car">
<interface name="com.trolltech.Examples.CarInterface">
<method name="accelerate"/>
<method name="decelerate"/>
<method name="turnLeft"/>
<method name="turnRight"/>
<method name="structer">
<annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="MyStruct"/>
<arg type="(sxs)" direction="out"/>
<arg type="x" direction="out"/>
</method>
<signal name="crashed"/>
</interface>
</node>
可以注意到:1.这个红色字体函数声明中,有两个返回参数。 2.第一个返回参数被声明成了自定义的类型MyStruct .
第二步,看看QT DBUS Binding工具 qdbusxml2cpp是怎么翻译这个XML文件
运行 qdbusxml2cpp -i mystruct.h -c CarAdaptor -a car_adaptor_p.h:car_adaptor.cpp car.xml
注意,这是服务器端运行的命令,客户端运行另一命令(qdbusxml2cpp -c CarInterface -p car_interface_p.h:car_interface.cpp -i mystruct.h car.xml) 这里不再描述。
第三步,看看生成的car_adaptor_p.h:car_adaptor.cpp文件,能发现下列问题
1. 生成了CarAdaptor,该类是QDBusAbstractAdaptor的一个子类。QDBusAbstractAdaptor是QT对象与DBUS绑定的桥梁。其基本用法是:
a: QDBusAbstractAdaptor其子类是一个普通 QObject对象的轻量封装对象,在此处QObject对象是提供DBUS服务的业务对象。在代码中,这个QObject对象称为“QDBusAbstractAdaptor的parent对象” ,在本例子中,这个业务对象是Car对象。
b:通过QDBusConnection::registerObject方法注册parent对象。(见第四步的main函数的逻辑部分)
2.CarAdaptor通过Q_CLASSINFO将DBUS访问的接口信息插入QT元数据描述中。
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "com.trolltech.Examples.CarInterface")
Q_CLASSINFO("D-Bus Introspection", ""
" <interface name=/"com.trolltech.Examples.CarInterface/" >/n"
" <method name=/"accelerate/" />/n"
" <method name=/"decelerate/" />/n"
" <method name=/"turnLeft/" />/n"
" <method name=/"turnRight/" />/n"
" <method name=/"structer/" >/n"
" <annotation value=/"MyStruct/" name=/"com.trolltech.QtDBus.QtTypeName.Out0/" />/n"
" <arg direction=/"out/" type=/"(sxs)/" />/n"
" <arg direction=/"out/" type=/"x/" />/n"
" </method>/n"
" <signal name=/"crashed/" />/n"
" </interface>/n"
"")
这里很难能透彻理解,可以运行qmake ,看看其生成的moc_car_adaptor_p.cpp文件,看看Q_CLASSINFO插入DBUS值对真正的代码是什么。
3.发现XML定义的structer函数原型被映射成:
public Q_SLOTS: MyStruct structer(qlonglong &out1);
其规律是第一个返回的参数被定义成返回值,第二个返回的参数被映射成引用的参数。
第四步,看看MyStruct 的自定义
class MyStruct {
public:
QString element1;
qlonglong element2;
QString element3;
};
Q_DECLARE_METATYPE(MyStruct)
inline void registerCommTypes() {
qDBusRegisterMetaType<MyStruct>();
}
QDBusArgument &operator<<(QDBusArgument &argument, const MyStruct &mystruct);
const QDBusArgument &operator>>(const QDBusArgument &argument,
MyStruct &mystruct);
1.定义MyStruct 的结构
2.声明MyStruct的元数据类型
3.向QT Dbus Binding注册MyStruct元数据类型
4.实现序列化与反序列化的函数 << | >> 用于从DBUS文本消息到MyStruct的双向转换。
5.Main 函数,主要逻辑如下:
new CarAdaptor(car);
QDBusConnection connection = QDBusConnection::sessionBus();
connection.registerObject("/Car", car);
connection.registerService("com.trolltech.CarExample");
6.调用流程日志
1.DBUS消息如下:
method call sender=:1.386 -> dest=:1.384 serial=166 path=/Car; interface=com.trolltech.Examples.CarInterface; member=structer
method return sender=:1.384 -> dest=:1.386 reply_serial=166
struct {
string "unu"
int64 2
string "trei"
}
int64 12345
2.程序调用日志显示调用路径
QDBusArgument &operator<<(mystruct.cpp)
Calling structer (carAdaptor.cpp)
Calling structer (car.cpp)
QDBusArgument &operator<<(mystruct.cpp)
从日志可以分析,第一条DBUS消息发出后,首先进入的是carAdaptor.cpp的structer函数,然后进入其业务对象Car的structer函数。最后运行结果返回,structer返回的MyStrct对象是序列化成DBUS消息被发送给客户端。
这里不解的地方是:为何QDBusArgument &operator<<被调用了两次?
分析:
当DBUS请求发送过来时,QT DBUS Binding应该是通过carAdaptor.cpp注册的DBUS 元数据信息找到了CarAdaptor对象,并且触发相关的方法,CarAdaptor对象将请求转发给其parent对象(Car),运行完成后由QT DBUS框架自动进行序列化成DBUS消息返回。
相关文章推荐
- 如何在Qt中使用自定义数据类型
- 如何在Qt中使用自定义数据类型
- Qt 支持自定义数据类型的托拽(Supporting Custom Drag Types)
- 让QT 4.7 支持DBUS调用中传递"aas(字符串二维数组)“ 数据据类型
- 如何在Qt中使用自定义数据类型
- 如何在Qt中使用自定义数据类型
- 三层中如何在服务器与客户端之间传输自定义的'Record'类型数据的例子
- 如何在Qt中使用自定义数据类型 (zz)
- Android开发之使用Intent进行自定义类型数据传输
- ibatis自定义数据类型在不支持中文的数据库存储汉字
- Qt 线程间信号槽传递自定义数据类型(qRegisterMetaType的使用)
- 利用Qt的QSetting类存储自定义数据类型所需准备 4000
- 如何实现WCF中的自定义集合类型传输
- Qt-信号和槽中使用自定义数据类型
- Hadoop(十):简单了解Hadoop数据类型,输入输出格式及用户如何自定义。
- 如何在EA(Enterprise Architect)中自定义数据类型(Data Type)---转
- QT中如何在ComboBox中设置存放自定义类型
- CArray使用简单介绍,如何添加标准数据类型,和自定义的类,或者自定义数据类型
- 如何让QVariant使用自定义的数据类型?
- 9-2 支持自定义数据类型的托拽(Supporting Custom Drag Types)