1 概述
D-Bus是一种高级的进程间通信机制。D-Bus最主要的用途是在Linux桌面环境为进程提供通信,同时能将Linux桌面环境和Linux内核事件作为消息传递到进程。D-Bus的主要概率为总线,注册后的进程可通过总线接收或传递消息,进程也可注册后等待内核事件响应,例如等待网络状态的转变或者计算机发出关机指令。
D-Bus是一个消息总线系统。D-Bus是三层架构的进程间通信系统,其中包括:
接口层:接口层由函数库libdbus提供,进程可通过该库使用D-Bus的能力。
总线层:总线层实际上是由D-Bus总线守护进程提供的。它在Linux系统启动时运行,负责进程间的消息路由和传递,其中包括Linux内核和Linux桌面环境的消息传递。
包装层:一系列基于特定应用程序框架的Wrapper库。
在QT中的包装层是libdbus-qt.
要查看Dbus总线上的服务和对象可以借助d-feet 和qdbusviewer
要发送信号可以使用dbus-send,要查看Dbus上的消息流可以使用dbus-monitor
基入QT的资料还比较的少,主要可以参考
http://www.cnblogs.com/wwang/archive/2010/10/27/1862552.html
其他的DBus的基本资料可以参考:
http://dotnet.cnblogs.com/page/76759/?page=1
http://blog.csdn.net/flowingflying/archive/2009/09/07/4527634.aspx
2 QT中Dbus的最简单的用法
这个最简单的用法是在使用中发现的,不需要在Dbus的守护进程上注册服务和注册对象。
注册了对象后:对象中的导出的槽就可以供其他的客户端来调用了。
注册了服务后:对象就有了一个公共名,没有注册是只有三个唯一名。
在发送端只需创建一个信号后发送即可,
例如:
1) 创建QT的DBus信号
QDBusMessage msg =QDBusMessage::createSignal("/hotel/path", "hotel.interface", "checkIn");
2) 给信号赋值
msg<<this->ui->checkInlineEdit->text().toInt();
3) 发射信号
QDBusConnection::sessionBus().send(msg);
在接受端同样只需要简单的两三步即可
1) 绑定信号
QDBusConnection::sessionBus().connect(QString(),QString(),"dbus.client. interface","Active",this,SLOT(ActiveEvent(int)));
2) 在槽中进行相关的处理
在ActiveEvent槽中执行你的应用程序需要对这个信号做出的反应即可。
这样的使用在DBUS的守护进程中没有服务,只有三个唯一名,没有公共名,也没有任何的信号、槽、属性。
可以通过d-feet、 qdbusviewe来查看。
可以通过dbus-monitor监视信号发送过程
可以参考示例DBusSignalMethod中DBusServerDBusSignal和DBusClientDBusSignal
这种用法主要是在服务端,需要在DBus的守护进程上注册对象和注册服务,其他的客户端就可以自由的调用了。
不过这种方式也有一个好处,调用是服务端的返回的参数就只发给调用的客户端,是一对一的,不像上面用信号的方式,发送的信号是一对多的。
D-Bus和QT4 (wwang's blog一蓑烟雨任平生)
http://www.cnblogs.com/wwang/archive/2010/10/27/1862552.html
在常规用法中,分客户端和服务端,
客户端有三种用法,服务端有两个用法。
3.1 客户端的用法1:使用QDBusMessage
1) 创建一个QDBusMessage的方法调用
a) QDBusMessage m = QDBusMessage::createMethodCall("hotel.server",
i. "/hotel/path",
ii. "hotel.interface",
iii. "checkIn");
2) 给方法传递参数
a) m<<this->ui->checkInlineEdit->text().toInt();
3) 调用方法
a) QDBusMessage response = QDBusConnection::sessionBus().call(m);
4) 判断方法的返回值
if (response.type() == QDBusMessage::ReplyMessage) {
// QDBusMessage的arguments不仅可以用来存储发送的参数,也用来存储返回值;
// 这里取得checkIn的返回值
int num_room = response.arguments().takeFirst().toInt();
qDebug("Got %d %s/n", num_room, (num_room > 1) ? "rooms" : "room");
} else
{
qDebug( "Check In fail!/n");
}
3.2客户端的用法2:使用DBusInterface
可以参考实例DBusInterface中的DBusServer和DBusClientInterface
1) 创建一个QDBusInterface的实例
QDBusInterface iface( "hotel.server",
"/hotel/path",
"hotel.interface", QDBusConnection::sessionBus());
if (!iface.isValid()) {
qDebug() << qPrintable(QDBusConnection::sessionBus().lastError().message());
exit(1);
}
2) 传递参数
int num_room;
num_room= this->ui->checkInlineEdit->text().toInt();
3) 呼叫远程的checkIn,参数为num_room
QDBusReply<int> reply = iface.call("checkIn", num_room);
4) 判断返回值
if (reply.isValid()) {
num_room = reply.value();
qDebug("Got %d %s/n", num_room, (num_room > 1) ? "rooms" : "room");
} else {
qDebug( "Check In fail!/n");
}
3.3 客户端的用法3:使用DBusProxy
DBusProxy可以使访问更加方便,就像访问本地类成员变量的方式访问远程的method
在使用这个类的时候要使用两个工具
qdbuscpp2xml和qdbusxml2cpp
利用qdbuscpp2xml –M –S hotel.h –o hotel.xml
在利用qdbusxml2cpp hotel.xml –p hotelInterface
在客户端的工程中添加这俩个文件。
1) 创建接口
a) hotel::interface myHotel("hotel.server",
a) "/hotel/path",
i. QDBusConnection::sessionBus());
2) 给参数赋值
i. int num_room;
ii. num_room= this->ui->checkInlineEdit->text().toInt();
3) 调用checkIn
a) QDBusPendingReply<int> reply = myHotel.checkIn(num_room);
4) 等待完成
a) reply.waitForFinished();
5) 判断返回值
if (reply.isValid()) {
num_room = reply.value();
qDebug("Got %d %s/n", num_room, (num_room > 1) ? "rooms" : "room");
} else {
qDebug( "Check In fail!/n");
}
3.4服务端的用法1:直接注册对象和服务
可以参考实例DBusMessage中的DBusServer
1) 创建连接
QDBusConnection bus = QDBusConnection::sessionBus();
// 在session bus上注册名为"com.test.hotel"的service
2) 注册服务
if (!bus.registerService("hotel.server")) {
a) qDebug() << bus.lastError().message();
b) exit(1);
}
3) 注册对象
if(! (bus.registerObject("/hotel/path", &my_hotel , QDBusConnection::ExportAllSlots)))
{
qDebug() << bus.lastError().message();
exit(1);
}
3.5 服务端的用法2:使用DBusAdapter
可以参考实例DBusAdapter中的DBusServerXML
QT4推荐使用Adapter来注册Object。
很多情况下,我们可能只需要把我们定义的类里的方法有选择的发布到Message Bus上,使用Adapter可以很方便的实现这种意图
1) 创建连接
QDBusConnection bus = QDBusConnection::sessionBus();
// 在session bus上注册名为"com.test.hotel"的service
2) 注册服务
if (!bus.registerService("hotel.server")) {
qDebug() << bus.lastError().message();
exit(1);
}
3) 创建Adaptor对象
myHotelAdaptor =new InterfaceAdaptor(&my_hotel);
4) 注册对象
if(! (bus.registerObject("/hotel/path", &my_hotel ,QDBusConnection::ExportAllSlots)))
{
qDebug() << bus.lastError().message();
exit(1);
}
4 QT中Dbus的特殊的用法(使用QT的信号)
在使用QT一段时间后,大家也许对QT的信号与槽很熟悉了,再来了一个DBus的信号与槽,大家可能很容易混淆了,想直接使用QT的信号与槽?
这样也是可以的,可以参照QT的例子程序 dbus-chat,中间就有这种用法的。
发射信号直接用QT的,绑定信号与槽也用QT的是不是很熟悉了。
具体的可以参考QT的实例dbus-chat
也可以参考实例QTSignalSlot中的DBusClientQTSignal和DBusServerQTSignal
发送信号端:
1 新建一个DBus服务
QDBusConnection bus = QDBusConnection::sessionBus();
2 注册对象(注册的时候必须注册this,这样this对象中的信号就可以直接发送到DBus上)
bus.registerObject("/hotel/path", this ,
QDBusConnection::ExportAllSlots|
QDBusConnection::ExportAllSignals);
接受信号端:
1 新建一个接口
myInterface= new hotel::interface(QString(),QString(),QDBusConnection::sessionBus(),this);
2 信号的绑定(注意:接收必须在DBus中注册的对象中接收)
QObject::connect(myInterface,SIGNAL(checkIn(int)),this,SLOT(checkInSlot(int)));
注意点:
1 信号的发射端要想信号发射到DBus上去,在对象的构造函数中必须,注册对象自己,必须使用this指针。例如:connection.registerobject(“/com/dbus/path”,this);
这样这个类中的所有的信号都可以直接用emit发射到DBus总线上。
2 信号的接受端绑定信号是可以使用QTDBus的绑定也可以直接使用QObject的绑定。
当使用Qobject的绑定时,QObject::connect(dbusInterface,SIGNAL(testMessage),this,SLOT(testEvent);
创建接口时,接口的头两个参数必须为空,例如:
dbusInterface =new dbus::test::interface(QString(),QString(),QDBusConnection::session(),this);
绑定的信号必须是已经导出的在interface文件有的。
当使用QDBus的绑定时,不论前两个参数是否为空,都可以正常的接受到信号
3 只有注册到DBus上去对象才能接受打DBus上的信号,其他的对象要接受DBus上的信号必须通过这个注册的对象将信号转发出来。
QObject::connect(myInterface,SIGNAL(queryReply(int)),this,SIGNAL(queryResult(int)));