進程間通訊-DBus

記一下:來自https://blog.csdn.net/lvliang2008/article/details/6304003

概述... 2

2 QTDbus的最簡單的用法... 3

3 QTDBus的常規用法... 4

3.1 客戶端的用法1:使用QDBusMessage. 4

3.2客戶端的用法2:使用DBusInterface. 4

3.3 客戶端的用法3:使用DBusProxy. 5

3.4服務端的用法1:直接註冊對象和服務... 6

3.5 服務端的用法2:使用DBusAdapter 6

4 QTDbus的特殊的用法(使用QT的信號) 7

 

 

概述

D-Bus是一種高級的進程間通信機制,它由freedesktop.org項目提供,使用GPL許可證發行。D-Bus最主要的用途是在Linux桌面環境爲進程提供通信,同時能將Linux桌面環境和Linux內核事件作爲消息傳遞到進程。D-Bus的主要概率爲總線,註冊後的進程可通過總線接收或傳遞消息,進程也可註冊後等待內核事件響應,例如等待網絡狀態的轉變或者計算機發出關機指令。目前,D-Bus已被大多數Linux發行版所採用,開發者可使用D-Bus實現各種複雜的進程間通信任務。

D-Bus是一個消息總線系統,其功能已涵蓋進程間通信的所有需求,並具備一些特殊的用途。D-Bus是三層架構的進程間通信系統,其中包括:

接口層:接口層由函數庫libdbus提供,進程可通過該庫使用D-Bus的能力。

總線層:總線層實際上是由D-Bus總線守護進程提供的。它在Linux系統啓動時運行,負責進程間的消息路由和傳遞,其中包括Linux內核和Linux桌面環境的消息傳遞。

包裝層:包裝層一系列基於特定應用程序框架的Wrapper庫。

 

QT中的Dbus是使用的Dbus的包裝層libdbus-qt.

要查看Dbus總線上的服務和對象可以藉助d-feet qdbusviewer

要發送信號可以使用dbus-send,要查看Dbus上的消息流可以使用dbus-monitor

 

QT Dbus是在QT4.2中才引進到QT中來的,還有很多的地方不是很完善,在網上DBus的資料比較多,不過很多都是基入GTK的,基入QT的資料還比較的少,主要可以參考

D-BusQT4 wwang's blog一蓑煙雨任平生)

http://www.cnblogs.com/wwang/archive/2010/10/27/1862552.html

 

其他的DBus的基本資料可以參考:

DBus學習筆記(博客園)

http://dotnet.cnblogs.com/page/76759/?page=1

愷風的CSDN博客

http://blog.csdn.net/flowingflying/archive/2009/09/07/4527634.aspx

 

 

 

2 QTDbus的最簡單的用法

       關於QT中的DBus的用法介紹的文章比較的少,網上只有這篇文章(國外的網站上可能有更多,只是沒有發現而已)和QT中的四個例子程序。

這個最簡單的用法是在使用中發現的,不需要在Dbus的守護進程上註冊服務和註冊對象。

註冊了對象後:對象中的導出的槽就可以供其他的客戶端來調用了。

註冊了服務後:對象就有了一個公共名,沒有註冊是隻有三個唯一名。

 

在發送端只需創建一個信號原後發送即可,

例如:

1)        創建QTDBus信號

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監視信號發送過程

可以參考示例DBusSignalMethodDBusServerDBusSignalDBusClientDBusSignal

 

 

3 QTDBus的常規用法

在以下這篇文章中已經很好的介紹了QT DBus的各種常規的用法了,在此就重複了,這種用法主要是在服務端,需要在DBus的守護進程上註冊對象和註冊服務,原後其他的客戶端就可以自由的調用了。

不過這種方式也有一個好處,調用是服務端的返回的參數就只發給調用的客戶端,是一對一的,不想上面的用信號的方式,信號的方式,發送的信號是一對多的。

D-BusQT4 wwang's blog一蓑煙雨任平生)

http://www.cnblogs.com/wwang/archive/2010/10/27/1862552.html

 

在也有幾個小的例子程序是根據D-BusQT4 wwang's blog一蓑煙雨任平生)的例子改編的。

在常規用法中也分客戶端和服務端的,

客戶端有三種用法,服務端有兩個用法。

3.1 客戶端的用法1:使用QDBusMessage

可以參考實例DBusMessage中的DBusServerDBusClient

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) {

// QDBusMessagearguments不僅可以用來存儲發送的參數,也用來存儲返回值;

            // 這裏取得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中的DBusServerDBusClientInterface

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中的DBusClientProxyDBusServer

DBusProxy可以使訪問更加方便,就像訪問本地類成員變量的方式訪問遠程的method

在使用這個類的時候要使用兩個工具

qdbuscpp2xmlqdbusxml2cpp

 

利用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 QTDbus的特殊的用法(使用QT的信號)

在使用QT一段時間後,大家也許對QT的信號與槽很熟悉了,再來了一個DBus的信號與槽,大家可能很容易混淆了,想直接使用QT的信號與槽?

這樣也是可以的,可以參照QT的例子程序 dbus-chat,中間就有這種用法的。

發射信號直接用QT的,綁定信號與槽也用QT的是不是很熟悉了。

具體的可以參考QT的實例dbus-chat

也可以參考實例QTSignalSlot中的DBusClientQTSignalDBusServerQTSignal

 

發送信號端:

新建一個DBus服務

QDBusConnection bus = QDBusConnection::sessionBus();

註冊對象(註冊的時候必須註冊this,這樣this對象中的信號就可以直接發送到DBus上)

bus.registerObject("/hotel/path", this ,

                           QDBusConnection::ExportAllSlots|

                           QDBusConnection::ExportAllSignals);

 

接受信號端:

新建一個接口

myInterface= new hotel::interface(QString(),QString(),QDBusConnection::sessionBus(),this);

信號的綁定(注意:接收必須在DBus中註冊的對象中接收)

QObject::connect(myInterface,SIGNAL(checkIn(int)),this,SLOT(checkInSlot(int)));

 

注意點:

信號的發射端要想信號發射到DBus上去,在對象的構造函數中必須,註冊對象自己,必須使用this指針。例如:connection.registerobject(“/com/dbus/path”,this);

這樣這個類中的所有的信號都可以直接用emit發射到DBus總線上。

 

信號的接受端綁定信號是可以使用QTDBus的綁定也可以直接使用QObject的綁定。

當使用Qobject的綁定時,QObject::connectdbusInterfaceSIGNALtestMessage),thisSLOTtestEvent);

創建接口時,接口的頭兩個參數必須爲空,例如:

dbusInterface =new dbus::test::interfaceQString(),QString(),QDBusConnection::session(),this);

綁定的信號必須是已經導出的在interface文件有的。

當使用QDBus的綁定時,不論前兩個參數是否爲空,都可以正常的接受到信號

 

只有註冊到DBus上去對象才能接受打DBus上的信號,其他的對象要接受DBus上的信號必須通過這個註冊的對象將信號轉發出來。

QObject::connect(myInterface,SIGNAL(queryReply(int)),this,SIGNAL(queryResult(int)));

 

源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章