DBUS与QDBUS的应用

转自: http://blog.chinaunix.net/uid-23023613-id-219094.html   稍有改动~


D-Bus概述


什么是D -Bus?

 

D-Bus是一种进程间通信的机制,它被设计成为一种低开销、低延迟的IPC,并被多种桌面环境(如KDE、GNOME等)所采用。
关于D -Bus的详细介绍可以参考freedesktop.org提供的两份文档,   D-Bus Tutorial    D-Bus Specification 。


基本概念


D -Bus提供了多种Message Bus用于应用程序之间的通信。通常,Linux发行版都会提供两种Message Bus:System Bus和Session Bus。System Bus 主要用于内核和一些系统全局的service之间通信;Session Bus 主要用于桌面应用程序之间的通信。
D-Bus中用于通信的基本单元叫做Message,Message的具体格式可以参考      D-Bus Specification
当应用程序连接到M   essage Bus上时,D-Bus会分配一个unique connection name,这个unique name通常的格式如":34-907"。Unique name以":"开头,后面的数字没有特别的意义,只是为了保证这个unique name的唯一性。
另外,应用程序还可以向M essage Bus请求一个well-known name,格式如同一个反置的域名,例如"com.mycompany.myapp"。当一个应用程序连接到Message Bus上时,可以拥有两种名称:unique connection name和well-known name。这两种名称的关系可以理解为网络上的IP地址和域名的关系。
在D -Bus规范里,unique connection name和well-known name都叫做Bus Name。这点比较奇怪,也比较拗口,Bus Name并不是Message Bus的名称,而是应用程序和Message Bus之间的连接的名称。
应用程序和Message Bus之间的连接也被称为Service,这样一来,把Bus Name称作Service Name在概念上会更清晰一点。
当应用程序连接到M essage Bus上时,该应用程序可以在Bus上创建一到多个Object(我们可以把D-Bus的object理解成面向对象语言里的object)。Service通过Object 为其他应用程序提供访问接口。因为在Message Bus上,一个应用程序可以对应多个Object,所以不同的Object必须由Object Path(类似于文件系统的路径)来区分。Object Path的格式如"/foo/bar"。
Serivce和Object Path之间相互独立,没有任何关联,注册时可以根据需要命名.

对于Service Name和Object Path,QT4文档中有一个类比还是比较直观的,如下图所示:


图中的ftp.example.com可以看作是Service Name,/pub/something可以看作是Object Path。

D-Bus通过Signal/Method来发送和接收Message。Signal/Method可以理解为QT4中的Signal/Slot这个概念。一个Object可以提供多个Method/Signal,这些Method/Signal的集合又组成了Interface。

因此,D-Bus的这些概念从大到小可以表示为:Message Bus->Service->Object->[Interface]->Method/Signal。

其中,Interface是可选的。


D -Bus  调试工具


常用的D -Bus调试工具有  D -Feet、qdbusviewer等。
在C   onsole窗口中键入qdbusviewer命令可以打开QT4自带的qdbusviewer  



如上图所示,我们可以通过q dbusviewer来调用Object在Message Bus上发布的所有Method。


D   -Bus 的 QT4 绑定


下面,我们通过一个实例来介绍D -Bus的QT4绑定。(参见hotel.pro)
我们在S ession bus上创建一个"com.test.hotel" service,通过这个service可以执行check in,check out和query三个动作。

创建S ervice并且注册Object

   // 用于建立到session bus的连接
    QDBusConnection bus = QDBusConnection::sessionBus();

   // 在session bus上注册名为"com.test.hotel"的service
    if (!bus.registerService("com.test.hotel")){
            qDebug()<< bus.lastError().message();
            exit(1);
    }
    Hotel my_hotel;

   // 注册名为"/hotel/registry"的object。
    // "QDBusConnection::ExportAllSlots"

    // 表示把类Hotel的所有Slot都导出为这个Object的method
    bus.registerObject("/hotel/registry",&my_hotel,
                       QDBusConnection::ExportAllSlots);
    return a.exec();
}


我们再看一下Hotel类的定义。


class Hotel:public QObject
{
    Q_OBJECT

   // 定义Interface名称为"com.test.hotel.registry"
    Q_CLASSINFO("D-Bus Interface","com.test.hotel.registry")
public:
    Hotel() { m_rooms = MAX_ROOMS;}
public slots:
    // Check in,参数为房间数,返回成功拿到的房间数
    int checkIn(int num_room);
    // Check out,参数为房间数,返回成功退回的房间数
    int checkOut(int num_room);
    // Query,用于查询目前还剩下的房间数
    int query();
private:
    int m_rooms;
    QReadWriteLock m_lock;
};


运行这个程序,我们可以使用qdbusviewer查看和操作这个Object。




通过QDBusMessage访问Service


在QT 4中,用QDBusMessage表示在D-Bus上发送和接收的Message。(参见checkin.pro)


       // 用来构造一个在D-Bus上传递的Message
        QDBusMessage m = QDBusMessage::createMethodCall("com.test.hotel",
                                                      "/hotel/registry",
                                                      "com.test.hotel.registry",
                                                      "checkIn");
        if (argc== 2){
                // 给QDBusMessage增加一个参数;
                // 这是一种比较友好的写法,也可以用setArguments来实现
                m << QString(argv[1]).toInt();
        }

       // 发送Message
        QDBusMessage response = QDBusConnection::sessionBus().call(m);
        // 判断Method是否被正确返回
        if (response.type()== QDBusMessage::ReplyMessage){
                // QDBusMessage的arguments不仅可以用来存储发送的参数,也用来存储返回值;
                // 这里取得checkIn的返回值
                int num_room = response.arguments().takeFirst().toInt();
                printf("Got %d %s\n", num_room,(num_room> 1)?"rooms" : "room");
        } else {
                fprintf(stderr,"Check In fail!\n");
        }


通过QDBusInterface 访问Service


在QT 4中,QDBusInterface可以更加方便的访问Service。(参见checkin2.pro)



       // 创建QDBusInterface
        QDBusInterface iface( "com.test.hotel", "/hotel/registry",
                              "com.test.hotel.registry",

                              QDBusConnection::sessionBus());
        if (!iface.isValid()){
                qDebug()<<                            

                     qPrintable(QDBusConnection::sessionBus(). lastError().message());
                exit(1);
        }

       // 呼叫远程的checkIn,参数为num_room
        QDBusReply<int> reply= iface.call("checkIn", num_room);
        if (reply.isValid()){
                num_room = reply.value();
                printf("Got %d %s\n", num_room,(num_room> 1)?"rooms" : "room");
        } else {
                fprintf(stderr,"Check In fail!\n");
        }

看,用QDB usInterface来访问Service是不是更加方便?


从D -Bus XML自动生成Proxy类


用QDB   usInterface访问Service已经非常方便了,但还不够直观。还有没有更直观的方法,就像访问本地类成员变量的方式访问远程的method?答案是Proxy。  
Proxy Object提供了一种更加直观的方式来访问Service,就好像调用本地对象的方法一样。  

概括的说,达成上述目标需要分三步走:

(1)使用工具 qdbuscpp2xml从hotel.h生成XML文件;
            qdbuscpp2xml -M hotel.h -o com.test.hotel.xml
(2)使用工具qdbusxml2cpp从XML文件生成继承自QDBusInterface的类;
            qdbusxml2cpp com.test.hotel.xml -i hotel.h -p hotelInterface
       这条命令会生成两个文件:hotelInterface.cpp和hotelInterface.h
(3)调用(2)生成的类来访问Service。

下面是举例(参见c heckin3.pro  ):


       // 初始化自动生成的Proxy类com::test::hotel::registry
        com::test::hotel::registry myHotel("com.test.hotel",
                                           "/hotel/registry",
                                           QDBusConnection::sessionBus());
        // 调用checkIn
        QDBusPendingReply<int> reply= myHotel.checkIn(num_room);
        // qdbusxml2cpp生成的Proxy类是采用异步的方式来传递Message,
        // 所以在此需要调用waitForFinished来等到Message执行完成
        reply.waitForFinished();
        if (reply.isValid()){
                num_room = reply.value();
                printf("Got %d %s\n", num_room,(num_room> 1)?"rooms" : "room");
        } else {
                fprintf(stderr,"Check In fail!\n");
        };


使用Adapter注册Object


如前文所述,我们可以直接把c lass Hotel注册为Message Bus上的一个Object,但这种方式并不是QT4所推荐的。QT4推荐使用Adapter来注册Object。
很多情况下,我们可能只需要把我们定义的类里的方法有选择的发布到M essage Bus上,使用Adapter可以很方便的实现这种意图。
以前文中的H otel为例,假设我们只需要把checkIn和checkOut发布到Message Bus上,应该怎么办?

(1)使用工具   qdbuscpp2xml从hotel.h生成XML文件;
            qdbuscpp2xml -M hotel.h -o com.test.hotel.xml  
(2)编辑com.test.hotel.xml,把其中的query部分去掉;
        即去掉以下三条语句:
        < method name="query">
              
        
(3)使用工具qdbusxml2cpp从XML文件生成继承自QDBusInterface的类;
            qdbusxml2cpp com.test.hotel.xml -i hotel.h -a hotelAdaptor
       这条命令会生成两个文件:hotelAdaptor.cpp和hotelAdaptor.h
(4)调用(3)生成的类来注册Object。

(参见hotel2.pro)


int main(int argc,char*argv[])
{
    QCoreApplication a(argc, argv);
    QDBusConnection bus = QDBusConnection::sessionBus();
    Hotel myHotel;
    // RegistryAdaptor是qdbusxml2cpp生成的Adaptor类
    RegistryAdaptor myAdaptor(&myHotel);
    if (!bus.registerService("com.test.hotel")){
            qDebug()<< bus.lastError().message();
            exit(1);
    }
    bus.registerObject("/hotel/registry",&myHotel);
    return a.exec();
}


运行这个应用程序,我们从q dbusviewer上可以看到,只有checkIn和checkOut两个method被发布。如下图所示:



自动启动Service

所谓自启动,是指在客户请求一个服务,但该服务还没有启动时,dbus会自动启动该服务程序.

我们需要在/u sr/share/dbus-1/services下面建立com.test.hotel.service文件,文件的内容如下:

[D-BUS Service]
Name=com.test.hotel
Exec=/path/to/your/hotel

这样,我们在访问com.test.hotel时,若它当前未启动,则dbus会自动运行Exec指定的程序。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DBus是一种用于进程间通信的消息总线系统,而CMakeLists.txt是用于构建和管理CMake项目的文件。在给定的引用中,第一个引用\[1\]展示了一个简单的DBus代码示例,其中使用了DBus库来初始化DBus连接。第二个引用\[2\]展示了一个使用了hello.hpp头文件的C++代码示例,该头文件定义了Calculate_sum_Of_Two_Number函数。第三个引用\[3\]展示了一个CMakeLists.txt文件示例,其中使用了add_library和target_link_libraries命令来生成和链接依赖库。因此,DBus和CMakeLists.txt是两个不同的概念,分别用于进程间通信和构建项目。 #### 引用[.reference_title] - *1* [CMAKE 中使用 FindPkgConfig](https://blog.csdn.net/CaspianSea/article/details/79890404)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [【cmake】CMakeList添加库|添加头文件|添加路径|add_executable、add_library、target_link_libraries的...](https://blog.csdn.net/weixin_42319496/article/details/125424628)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值