zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    JavaScript
    94.Binary Tree Inorder Traversal
    144.Binary Tree Preorder Traversal
    106.Construct Binary Tree from Inorder and Postorder Traversal
    105.Construct Binary Tree from Preorder and Inorder Traversal
    90.Subsets II
    78.Subsets
    83.Merge Sorted Array
    80.Remove Duplicates from Sorted Array II
    79.Word Search
  • 原文地址:https://www.cnblogs.com/findumars/p/7487887.html
Copyright © 2011-2022 走看看