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


    一、简介

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

    二、详解之Qt代码

    1、代码一

    (1)test.h

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

    (2)test.cpp

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

    (3)test_adaptor.h

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

    (4)test_adaptor.cpp

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

    (5)main.cpp

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

    (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信号,得到输出结果:

           然后输入:dbus-monitor --session "type='signal',interface='com.asianux.btagent.adaptor',member='stateChange'",监控,从应用程序发出的DBus信号:

            也可以通过qt自带的工具qdbusviewer查看和操作相应的DBus信号:

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

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

    makefile:

    [html] view plain copy
     
    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程序):

    2、代码二

    (1)qdbus.h

    [html] view plain copy
     
    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.   
    10. public:  
    11. //     DeviceManager(){}  
    12. //     ~DeviceManager(){}  
    13. public slots:  
    14.     void slotInterface(QString);  
    15. };  
    16. #endif // QDBUS  

    (2)main.cpp

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

    运行结果:

    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 ", num_room,(num_room> 1)?"rooms": "room");
            } else {
                    fprintf(stderr,"Check In fail! ");
            }

    通过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 ", num_room,(num_room> 1)?"rooms": "room");
            } else {
                    fprintf(stderr,"Check In fail! ");
            }

    看,用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 ", num_room,(num_room> 1)?"rooms": "room");
            } else {
                    fprintf(stderr,"Check In fail! ");
            };

    使用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:

    [html] view plain copy
     
    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 当用户自定义信号使用。

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

    运行程序,打开另终端发送killall -HUP ./sighupcode,则会处理SIGHUP信号:

    三、详解之C代码

    1、代码

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

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

    (2)method_recv.c

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

    (3)编译运行(先运行method_send)
    编译method_send.c:

    编译method_recv.c(得到运行结果):

    四、总结

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

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

  • 相关阅读:
    SQL Server-数据库架构和对象、定义数据完整性(二)
    SQL Server-语句类别、数据库范式、系统数据库组成(一)
    ASP.NET WebAPi之断点续传下载(下)
    ConcurrentDictionary线程不安全么,你难道没疑惑,你难道弄懂了么?
    ASP.NET WebAPi之断点续传下载(中)
    ASP.NET WebAPi之断点续传下载(上)
    ASP.NET WebAPi(selfhost)之文件同步或异步上传
    JSTL fn:contains()函数
    用jstl标签判断一个字符串是否包含了另一个字符串
    fn:replace()函数
  • 原文地址:https://www.cnblogs.com/findumars/p/7487887.html
Copyright © 2020-2023  润新知