Qt浅谈之二十七进程间通信之QtDBus

一、简介

DBus的出现,使得Linux进程间通信更加便捷,不仅可以和用户空间应用程序进行通信,而且还可以和内核的程序进行通信,DBus使得Linux变得更加智能,更加具有交互性。
        DBus分为两种类型:system bus(系统总线),用于系统(Linux)和用户程序之间进行通信和消息的传递;session bus(回话总线),用于桌面(GNOME, KDE等)用户程序之间进行通信。

二、详解之Qt代码

1、代码一

(1)test.h

  1. #ifndef  TEST_H
  2. #define  TEST_H
  3. #include  <QtCore>
  4. #include  <QTimer>
  5. class Test : public QObject
  6. {
  7. Q_OBJECT
  8. public:
  9. Test();
  10. public slots:
  11. QString testStart();
  12. void changeTest();
  13. signals:
  14. void stateChange(QString str);
  15. private:
  16. QTimer *timer;
  17. };
  18. #endif  /*TEST_H*/

(2)test.cpp

  1. #include "test.h"
  2. Test::Test()
  3. {
  4. qDebug() << "===========test init===========";
  5. timer = new QTimer;
  6. connect(timer, SIGNAL(timeout()), this, SLOT(changeTest()));
  7. }
  8. QString Test::testStart()
  9. {
  10. qDebug() << "+++++++QtDBus test++++++++++";
  11. QString tmp;
  12. tmp = QString("OFF");
  13. qDebug() << tmp;
  14. if (timer->isActive()) {
  15. timer->stop();
  16. }
  17. timer->start(2000);
  18. return tmp;
  19. }
  20. void Test::changeTest()
  21. {
  22. QString tmp;
  23. tmp = QString("ON");
  24. qDebug() << "+++++++++++++++++++" << tmp;
  25. emit stateChange(tmp);
  26. }

(3)test_adaptor.h

  1. #include    "test_adaptor.h"
  2. #include    <QtCore>
  3. TestInterfaceAdaptor::TestInterfaceAdaptor(QObject *parent)
  4. :QDBusAbstractAdaptor(parent)
  5. {
  6. qDebug() << "***************TestInterfaceAdaptor::TestInterfaceAdaptor**************";
  7. setAutoRelaySignals(true);  //connection of the signals on the parent
  8. }
  9. TestInterfaceAdaptor::~TestInterfaceAdaptor()
  10. {
  11. }
  12. QString TestInterfaceAdaptor::test()
  13. {
  14. QString out;
  15. QMetaObject::invokeMethod(parent(), "testStart",Q_RETURN_ARG(QString, out));
  16. qDebug() << "==========" << out;
  17. return out;
  18. }

(4)test_adaptor.cpp

  1. #ifndef  TEST_ADAPTOR_H
  2. #define  TEST_ADAPTOR_H
  3. #include  <QtCore/QObject>
  4. #include  <QtDBus/QtDBus>
  5. /****
  6. **dbus-send --session --print-reply --dest=com.asianux.btagent /  com.asianux.btagent.adaptor.test
  7. **dbus-monitor --session \ "type='signal',interface='com.asianux.btagent.adaptor',member='stateChange'"
  8. *****/
  9. class TestInterfaceAdaptor : public QDBusAbstractAdaptor
  10. {
  11. Q_OBJECT
  12. Q_CLASSINFO("D-Bus Interface", "com.asianux.btagent.adaptor")
  13. Q_CLASSINFO("D-Bus Introspection", ""
  14. "  <interface name=\"com.asianux.btagent.adaptor\">\n"
  15. "    <method name=\"test\">\n"
  16. "      <arg name=\"state\" type=\"s\" direction=\"out\"/>\n"
  17. "    </method> \n"
  18. "    <signal name=\"stateChange\"> \n"
  19. "       <arg type=\"s\" direction=\"out\"/>\n"
  20. "    </signal> \n"
  21. "  </interface>\n"
  22. "")
  23. public:
  24. TestInterfaceAdaptor(QObject *parent);
  25. virtual ~TestInterfaceAdaptor();
  26. public:
  27. public slots:
  28. QString test();
  29. signals:
  30. void stateChange(QString str);
  31. };
  32. #endif  /*TEST_ADAPTOR_H*/

(5)main.cpp

  1. #include  <QApplication>
  2. #include  <QtDBus>
  3. #include <QDebug>
  4. #include  "test_adaptor.h"
  5. #include  "test.h"
  6. int main(int argc,char *argv[])
  7. {
  8. QApplication app(argc,argv);
  9. Test *test = new Test();
  10. new TestInterfaceAdaptor(test);
  11. QDBusConnection conn = QDBusConnection::sessionBus();
  12. conn.registerObject("/",test);
  13. conn.registerService("com.asianux.btagent");
  14. return app.exec();
  15. }

(6)运行

可以在linux终端发送(dbus-send)和监控dbus(dbus-monitor)的信息。 dbus-send调用远程方法的一般形式是:$ dbus-send [--system | --session] --type=method_call --print-reply --dest=连接名 对象路径 接口名.方法名 参数类型:参数值 参数类型:参数值,dbus-send支持的参数类型包括:string, int32, uint32, double, byte, boolean。
       启动程序后,先执行:dbus-send --session --print-reply --dest=com.asianux.btagent /  com.asianux.btagent.adaptor.test,发送dbus信号,得到输出结果:
Qt浅谈之二十七进程间通信之QtDBus
       然后输入:dbus-monitor --session \ "type='signal',interface='com.asianux.btagent.adaptor',member='stateChange'",监控,从应用程序发出的DBus信号:
Qt浅谈之二十七进程间通信之QtDBus
        也可以通过qt自带的工具qdbusviewer查看和操作相应的DBus信号:
Qt浅谈之二十七进程间通信之QtDBus

(7)除了上述方法,也可以使用glib的程序进行DBus通信。
main.c:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <glib.h>
  4. #include <dbus/dbus-glib.h>
  5. #include <dbus/dbus.h>
  6. static void bt_manager_changed_cb (DBusGProxy *proxy,
  7. const gchar *state,
  8. gpointer user_data)
  9. {
  10. printf("state = %s\n",state);
  11. }
  12. int main(int argc,char *argv[])
  13. {
  14. GMainLoop *loop = g_main_loop_new(NULL,TRUE);
  15. g_type_init();
  16. GError * error = NULL;
  17. DBusGConnection *gconn = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
  18. DBusGProxy *m_proxy = dbus_g_proxy_new_for_name(gconn, "com.asianux.btagent","/","com.asianux.btagent.adaptor");
  19. char *str = NULL;
  20. dbus_g_proxy_call(m_proxy, "test", &error,
  21. G_TYPE_INVALID,
  22. G_TYPE_STRING,&str,
  23. G_TYPE_INVALID);
  24. dbus_g_proxy_add_signal (m_proxy,
  25. "stateChange",
  26. G_TYPE_STRING,
  27. G_TYPE_INVALID);
  28. dbus_g_proxy_connect_signal (m_proxy,
  29. "stateChange",
  30. G_CALLBACK (bt_manager_changed_cb),
  31. NULL,
  32. NULL);
  33. printf("str = %s\n",str);
  34. g_main_loop_run(loop);
  35. }

makefile:

  1. all:
  2. gcc -g main.c -o test `pkg-config --cflags --libs dbus-1 gthread-2.0 glib-2.0 dbus-glib-1`
  3. clean:
  4. rm -rf *.o test

运行结果(先启动最上的服务器qt程序):
Qt浅谈之二十七进程间通信之QtDBus

2、代码二

(1)qdbus.h

  1. #ifndef QDBUS
  2. #define QDBUS
  3. #include <QtCore>
  4. /*dbus-send --session --print-reply --dest=com.asianux.btagent2 / com.asianux.btagent2.interface.slotInterface string:"helloworld"*/
  5. class DeviceManager : public QObject
  6. {
  7. Q_OBJECT
  8. Q_CLASSINFO("D-Bus Interface", "com.asianux.btagent2.interface")
  9. public:
  10. //     DeviceManager(){}
  11. //     ~DeviceManager(){}
  12. public slots:
  13. void slotInterface(QString);
  14. };
  15. #endif // QDBUS

(2)main.cpp

  1. #include <QCoreApplication>
  2. #include <QObject>
  3. #include <QtDBus>
  4. #include "qdbus.h"
  5. void DeviceManager::slotInterface(QString str)
  6. {
  7. qDebug() << "D-Bus Interface(com.asianux.btagent2.interface):" << str;
  8. }
  9. int main(int argc, char *argv[])
  10. {
  11. QCoreApplication a(argc, argv);
  12. QDBusConnection bus = QDBusConnection::sessionBus();
  13. if(!bus.registerService("com.asianux.btagent2")){
  14. qDebug() << bus.lastError().message();
  15. exit(1);
  16. }
  17. DeviceManager *deviceManager = new DeviceManager();
  18. bus.registerObject("/", deviceManager, QDBusConnection::ExportAllSlots);
  19. return a.exec();
  20. }

运行结果:

Qt浅谈之二十七进程间通信之QtDBus

3、其他网上代码

D-Bus的QT4绑定

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

创建Service并且注册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
在QT4中,用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

在QT4中,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");
        }

看,用QDBusInterface来访问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。
下面是举例(参见checkin3.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

如前文所述,我们可以直接把class Hotel注册为Message Bus上的一个Object,但这种方式并不是QT4所推荐的。QT4推荐使用Adapter来注册Object。
很多情况下,我们可能只需要把我们定义的类里的方法有选择的发布到Message Bus上,使用Adapter可以很方便的实现这种意图。
以前文中的Hotel为例,假设我们只需要把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">
               <arg type="i" direction="out"/>
        </method>
(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();
}

运行这个应用程序,我们从qdbusviewer上可以看到,只有checkIn和checkOut两个method被发布。

自动启动Service
D-Bus系统提供了一种机制可以在访问某个service时,自动把该程序运行起来。
我们需要在/usr/share/dbus-1/services下面建立com.test.hotel.service文件,文件的内容如下:
[D-BUS Service]
Name=com.test.hotel
Exec=/path/to/your/hotel
这样,我们在访问Hotel的method之前,就不必手动运行该应用程序了。

4、其他细节

(1)如果想使用system bus(自启动服务参考上述),需要在/etc/dbus-1/system.d/目录下创建一个配置文件my.conf:

  1. <!DOCTYPE busconfig PUBLIC
  2. "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
  3. "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
  4. <busconfig>
  5. <policy context="default">
  6. <allow own="com.asianux.btagent2"/>
  7. <allow send_destination="com.asianux.btagent2"/>
  8. <allow receive_sender="com.asianux.btagent2"/>
  9. </policy>
  10. </busconfig>

(2)可以参考通过QDbus实现的Qt检测U盘的例子:http://download.csdn.net/detail/taiyang1987912/8686677
(3)除了DBus,也可使用SIGHUP信号用于进程间通信,比如重写了配置文件,又不想重启程序就让配置生效,可以往该程序的进程发送一个SIGHUP信号:killall -HUP <进程名称>或kill -HUP <进程号>,可能因以前的系统没有提供用户自定义信号 SIGUSR1 和 SIGUSR1 ,而对于一个没有终端的守护进程来说是不可能收到 SIGHUP 信号的,所以就把 SIGHUP 当用户自定义信号使用。

  1. #include<stdio.h>
  2. #include <stdlib.h>
  3. #include<signal.h>
  4. char**args;
  5. void exithandle(int sig)
  6. {
  7. printf("%s:(%d)sighup received\n", args[0], sig);
  8. exit(0);
  9. }
  10. int main(int argc,char **argv)
  11. {
  12. args = argv;
  13. signal(SIGHUP,exithandle);
  14. while(1) sleep(1);
  15. return 0;
  16. }

运行程序,打开另终端发送killall -HUP ./sighupcode,则会处理SIGHUP信号:
Qt浅谈之二十七进程间通信之QtDBus

三、详解之C代码

1、代码

使用C语言调用dbus的底层函数编写一个远程调用的示例代码,代码很简单,没使用GObject等一些复杂的库。
(1)method_send.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <dbus/dbus-glib.h>
  5. #include <dbus/dbus.h>
  6. #include <unistd.h>
  7. /*gcc -o method_send method_send.c -I/usr/include/glib-2.0 -I/usr/include/dbus-1.0 -I/usr/lib64/glib-2.0/include -I/usr/lib64/dbus-1.0/include -lglib-2.0 -ldbus-glib-1*/
  8. void reply_to_method_call(DBusMessage * msg, DBusConnection * conn)
  9. {
  10. DBusMessage * reply;
  11. DBusMessageIter arg;
  12. char * param = NULL;
  13. dbus_bool_t stat = TRUE;
  14. dbus_uint32_t level = 2010;
  15. dbus_uint32_t serial = 0;
  16. //从msg中读取参数,这个在上一次学习中学过
  17. if(!dbus_message_iter_init(msg,&arg))
  18. printf("Message has noargs\n");
  19. else if(dbus_message_iter_get_arg_type(&arg)!= DBUS_TYPE_STRING)
  20. printf("Arg is notstring!\n");
  21. else
  22. dbus_message_iter_get_basic(&arg,& param);
  23. if(param == NULL) return;
  24. //创建返回消息reply
  25. reply = dbus_message_new_method_return(msg);
  26. //在返回消息中填入两个参数,和信号加入参数的方式是一样的。这次我们将加入两个参数。
  27. dbus_message_iter_init_append(reply,&arg);
  28. if(!dbus_message_iter_append_basic(&arg,DBUS_TYPE_BOOLEAN,&stat)){
  29. printf("Out ofMemory!\n");
  30. exit(1);
  31. }
  32. if(!dbus_message_iter_append_basic(&arg,DBUS_TYPE_UINT32,&level)){
  33. printf("Out ofMemory!\n");
  34. exit(1);
  35. }
  36. //发送返回消息
  37. if( !dbus_connection_send(conn, reply,&serial)){
  38. printf("Out of Memory\n");
  39. exit(1);
  40. }
  41. dbus_connection_flush (conn);
  42. dbus_message_unref (reply);
  43. }
  44. void listen_dbus()
  45. {
  46. DBusMessage * msg;
  47. DBusMessageIter arg;
  48. DBusConnection * connection;
  49. DBusError err;
  50. int ret;
  51. char * sigvalue;
  52. dbus_error_init(&err);
  53. //创建于session D-Bus的连接
  54. connection =dbus_bus_get(DBUS_BUS_SESSION, &err);
  55. if(dbus_error_is_set(&err)){
  56. fprintf(stderr,"ConnectionError %s\n",err.message);
  57. dbus_error_free(&err);
  58. }
  59. if(connection == NULL)
  60. return;
  61. //设置一个BUS name:test.wei.dest
  62. ret =dbus_bus_request_name(connection,"test.wei.dest",DBUS_NAME_FLAG_REPLACE_EXISTING,&err);
  63. if(dbus_error_is_set(&err)){
  64. fprintf(stderr,"Name Error%s\n",err.message);
  65. dbus_error_free(&err);
  66. }
  67. if(ret !=DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
  68. return;
  69. //要求监听某个singal:来自接口test.signal.Type的信号
  70. dbus_bus_add_match(connection,"type='signal',interface='test.signal.Type'",&err);
  71. dbus_connection_flush(connection);
  72. if(dbus_error_is_set(&err)){
  73. fprintf(stderr,"Match Error%s\n",err.message);
  74. dbus_error_free(&err);
  75. }
  76. while(1){
  77. dbus_connection_read_write(connection,0);
  78. msg =dbus_connection_pop_message (connection);
  79. if(msg == NULL){
  80. sleep(1);
  81. continue;
  82. }
  83. if(dbus_message_is_signal(msg,"test.signal.Type","Test")){
  84. if(!dbus_message_iter_init(msg,&arg))
  85. fprintf(stderr,"Message Has no Param");
  86. else if(dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_STRING)
  87. g_printerr("Param isnot string");
  88. else
  89. dbus_message_iter_get_basic(&arg,&sigvalue);
  90. }else if(dbus_message_is_method_call(msg,"test.method.Type","Method")){
  91. //我们这里面先比较了接口名字和方法名字,实际上应当现比较路径
  92. if(strcmp(dbus_message_get_path(msg),"/test/method/Object") == 0)
  93. reply_to_method_call(msg,connection);
  94. }
  95. dbus_message_unref(msg);
  96. }
  97. }
  98. int main( int argc , char ** argv)
  99. {
  100. listen_dbus();
  101. return 0;
  102. }

(2)method_recv.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <dbus/dbus-glib.h>
  5. #include <dbus/dbus.h>
  6. #include <unistd.h>
  7. /*gcc -o method_recv method_recv.c -I/usr/include/glib-2.0 -I/usr/include/dbus-1.0 -I/usr/lib64/glib-2.0/include -I/usr/lib64/dbus-1.0/include -lglib-2.0 -ldbus-glib-1*/
  8. //建立与session D-Bus daemo的连接,并设定连接的名字,相关的代码已经多次使用过了
  9. DBusConnection * connect_dbus()
  10. {
  11. DBusError err;
  12. DBusConnection * connection;
  13. int ret;
  14. //Step 1: connecting session bus
  15. dbus_error_init(&err);
  16. connection =dbus_bus_get(DBUS_BUS_SESSION, &err);
  17. if(dbus_error_is_set(&err)){
  18. fprintf(stderr,"ConnectionErr : %s\n",err.message);
  19. dbus_error_free(&err);
  20. }
  21. if(connection == NULL)
  22. return NULL;
  23. //step 2: 设置BUS name,也即连接的名字。
  24. ret =dbus_bus_request_name(connection,"test.wei.source",DBUS_NAME_FLAG_REPLACE_EXISTING,&err);
  25. if(dbus_error_is_set(&err)){
  26. fprintf(stderr,"Name Err :%s\n",err.message);
  27. dbus_error_free(&err);
  28. }
  29. if(ret !=DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
  30. return NULL;
  31. return connection;
  32. }
  33. void send_a_method_call(DBusConnection * connection,char * param)
  34. {
  35. DBusError err;
  36. DBusMessage * msg;
  37. DBusMessageIter    arg;
  38. DBusPendingCall * pending;
  39. dbus_bool_t * stat;
  40. dbus_uint32_t * level;
  41. dbus_error_init(&err);
  42. //针对目的地地址,请参考图,创建一个method call消息。Constructs a new message to invoke a method on a remote object.
  43. msg =dbus_message_new_method_call ("test.wei.dest","/test/method/Object","test.method.Type","Method");
  44. if(msg == NULL){
  45. g_printerr("MessageNULL");
  46. return;
  47. }
  48. //为消息添加参数。Appendarguments
  49. dbus_message_iter_init_append(msg, &arg);
  50. if(!dbus_message_iter_append_basic(&arg, DBUS_TYPE_STRING,&stat)){
  51. g_printerr("Out of Memory!");
  52. exit(1);
  53. }
  54. //发送消息并获得reply的handle。Queues amessage to send, as withdbus_connection_send() , but also returns aDBusPendingCall used to receive a reply to the message.
  55. if(!dbus_connection_send_with_reply (connection, msg,&pending, -1)){
  56. g_printerr("Out of Memory!");
  57. exit(1);
  58. }
  59. if(pending == NULL){
  60. g_printerr("Pending CallNULL: connection is disconnected ");
  61. dbus_message_unref(msg);
  62. return;
  63. }
  64. dbus_connection_flush(connection);
  65. dbus_message_unref(msg);
  66. //waiting a reply,在发送的时候,已经获取了methodreply的handle,类型为DBusPendingCall。
  67. // block until we recieve a reply, Block until the pendingcall is completed.
  68. dbus_pending_call_block (pending);
  69. //get the reply message,Gets thereply, or returns NULL if none has been received yet.
  70. msg =dbus_pending_call_steal_reply (pending);
  71. if (msg == NULL) {
  72. fprintf(stderr, "ReplyNull\n");
  73. exit(1);
  74. }
  75. // free the pendingmessage handle
  76. dbus_pending_call_unref(pending);
  77. // read the parameters
  78. if(!dbus_message_iter_init(msg, &arg))
  79. fprintf(stderr, "Message hasno arguments!\n");
  80. else if (dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_BOOLEAN)
  81. fprintf(stderr, "Argument isnot boolean!\n");
  82. else
  83. dbus_message_iter_get_basic(&arg, &stat);
  84. if (!dbus_message_iter_next(&arg))
  85. fprintf(stderr, "Message hastoo few arguments!\n");
  86. else if (dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_UINT32 )
  87. fprintf(stderr, "Argument isnot int!\n");
  88. else
  89. dbus_message_iter_get_basic(&arg, &level);
  90. printf("Got Reply: %d,%d\n", stat, level);
  91. dbus_message_unref(msg);
  92. }
  93. int main( int argc , char ** argv)
  94. {
  95. DBusConnection * connection;
  96. connection = connect_dbus();
  97. if(connection == NULL)
  98. return -1;
  99. send_a_method_call(connection,"Hello, D-Bus");
  100. return 0;
  101. }

(3)编译运行(先运行method_send)
编译method_send.c:
Qt浅谈之二十七进程间通信之QtDBus
编译method_recv.c(得到运行结果):
Qt浅谈之二十七进程间通信之QtDBus

四、总结

(1)本文仅提供代码的测试,其他的具体函数的意义请查阅相应的帮助文档。
(2)源码已经打包上传到csdn上,可登录下载(http://download.csdn.net/detail/taiyang1987912/8687183)。
(3)若有建议,请留言,在此先感谢!

http://blog.csdn.net/taiyang1987912/article/details/45642079

上一篇:ASP.NET Core Web 应用程序系列(一)- 使用ASP.NET Core内置的IoC容器DI进行批量依赖注入(MVC当中应用)


下一篇:Player启动时提示 "System.InvalidOperationException:无法加载计数器名称数据