和菜鳥一起學linux之DBUS基礎學習記錄


D-Bus三層架構

D-Bus是一個為應用程序間通信的消息總線系統, 用於進程之間的通信。它是個3層架構的IPC 系統,包括:

1、函數庫libdbus ,用於兩個應用程序互相聯系和交互消息。

2、一個基於libdbus構造的消息總線守護進程,可同時與多個應用程序相連,並能把來自一個應用程序的消息路由到0或者多個其他程序。

3、基於特定應用程序框架的封裝庫或捆綁(wrapper libraries or bindings )。例如,libdbus-glib和libdbus-qt,還有綁定在其他語言,例如Python的。大多數開發者都是使用這些封裝庫的API,因為它們簡化了D-Bus編程細節。libdbus被有意設計成為更高層次綁定的底層后端(low-levelbackend )。大部分libdbus的 API僅僅是為了用來實現綁定。

 

總線

  在D-Bus中,“bus”是核心的概念,它是一個通道:不同的程序可以通過這個通道做些操作,比如方法調用、發送信號和監聽特定的信號。在一台機器上總線守護有多個實例(instance)。這些總線之間都是相互獨立的。

一個持久的系統總線(system bus):

它在引導時就會啟動。這個總線由操作系統和后台進程使用,安全性非常好,以使得任意的應用程序不能欺騙系統事件。它是桌面會話和操作系統的通信,這里操作系統一般而言包括內核和系統守護進程。這種通道的最常用的方面就是發送系統消息,比如:插入一個新的存儲設備;有新的網絡連接;等等。

還將有很多會話總線(session buses):

這些總線當用戶登錄后啟動,屬於那個用戶私有。它是用戶的應用程序用來通信的一個會話總線。同一個桌面會話中兩個桌面應用程序的通信,可使得桌面會話作為整體集成在一起以解決進程生命周期的相關問題。這在GNOME和KDE桌面中大量使用。

  對於一些遠程的工作站,在system bus中可能會有一些問題,例如熱插拔,是否需要通知遠端的terminal,這會使得kernel暴露一些設備的能力,不過,我們現在關心D-Bus,是因為手持終端設備的使用,這些將不會出現。在Internet Tablet,也包括我們的手機系統,所有的應用程序都是使用一個用戶ID運行的,所以只有一個會話通道,這一點是和Linux桌面系統是有明顯區別的。

  D-Bus是低延遲而且低開銷的,設計得小而高效,以便最小化傳送的往返時間。另外,協議是二進制的,而不是文本的,這樣就排除了費時的序列化過程。從開發者的角度來看,D-BUS 是易於使用的。有線協議容易理解,客戶機程序庫以直觀的方式對其進行包裝。D-Bus的主要目的是提供如下的一些更高層的功能:

A、結構化的名字空間

B、獨立於架構的數據格式

C、支持消息中的大部分通用數據元素

D、帶有異常處理的通用遠程調用接口

E、支持廣播類型的通信

 

Bus daemon總線守護

       Bus daemon是一個特殊的進程:這個進程可以從一個進程傳遞消息給另外一個進程。當然了,如果有很多applications鏈接到這個通道上,這個 daemon進程就會把消息轉發給這些鏈接的所有程序。在最底層,D-Bus只支持點對點的通信,一般使用本地套接字(AF_UNIX)在應用和bus daemon之間通信。D-Bus的點對點是經過busdaemon抽象過的,由busdaemon來完成尋址和發送消息,因此每個應用不必要關心要把消息發給哪個進程。D-Bus發送消息通常包含如下步驟(正常情況下):

創建和發送消息 給后台bus daemon進程,這個過程中會有兩個上下文的切換。

后台bus daemon進程會處理該消息,並轉發給目標進程,這也會引起上下文的切換目標程序接收到消息,然后根據消息的種類,做不同的響應:要么給個確認、要么應答、還有就是忽略它。最后一種情況對於“通知”類型的消息而言,前兩種都會引起進一步的上下文切換。

綜上原因,如果你准備在不同的進程之間傳遞大量的數據,D-Bus可能不是最有效的方法,最有效的方法是使用共享內存,但是對共享內存的管理也是相當復雜的。

 

D-Bus進程通信簡單框架

 

D-Bus常見概念

原生對象和對象路徑

所有使用D-BUS的應用程序都包含一些對象, 當經由一個D-BUS連接收到一條消息時,該消息是被發往一個對象而不是整個應用程序。在開發中程序框架定義着這樣的對象,例如JAVA,GObject,QObject等等,在D-Bus中成為native object。

對於底層的D-Bus協議,即libdbus API,並不理會這些native object,它們使用的是一個叫做object path的概念。通過object path,高層編程可以為對象實例進行命名,並允許遠程應用引用它們。這些名字看起來像是文件系統路徑,例如一個對象可能叫做“/org/kde/kspread/sheets/3/cells/4/5”。易讀的路徑名是受鼓勵的做法,但也允許使用諸如“/com/mycompany/c5yo817y0c1y1c5b”等,只要它可以為你的應用程序所用。Namespacing的對象路徑以開發者所有的域名開始(如 /org/kde)以避免系統不同代碼模塊互相干擾。

簡單地說:一個應用創建對象實例進行D-Bus的通信,這些對象實例都有一個名字,命名方式類似於路徑,例如/com/mycompany,這個名字在全局(session或者system)是唯一的,用於消息的路由。

 

方法和信號Methodsand Signals

每一個對象有兩類成員:方法和信號。方法就是JAVA中同樣概念,方法是一段函數代碼,帶有輸入和輸出。信號是廣播給所有興趣的其他實體,信號可以帶有數據payload。

在 D-BUS 中有四種類型的消息:方法調用(method calls)、方法返回(method returns)、信號(signals)和錯誤(errors)。要執行 D-BUS 對象的方法,您需要向對象發送一個方法調用消息。它將完成一些處理(就是執行了對象中的Method,Method是可以帶有輸入參數的。)並返回,返回消息或者錯誤消息。信號的不同之處在於它們不返回任何內容:既沒有“信號返回”消息,也沒有任何類型的錯誤消息。

 

接口Interface

每一個對象支持一個或者多個接口,接口是一組方法和信號,接口定義一個對象實體的類型。D-Bus對接口的命名方式,類似org.freedesktop.Introspectable。開發人員通常將使用編程語言類的的名字作為接口名字。

 

Proxies代理

代理對象用來表示其他的remote object。當我們觸發了proxy對象的method時,將會在D-Bus上發送一個method_call的消息,並等待答復,根據答復返回。使用非常方便,就像調用一個本地的對象。

 

Bus Names總線名字

  當一個應用連接到bus daemon,daemon立即會分配一個名字給這個連接,稱為unique connection name ,這個唯一標識的名字以冒號:開頭,例如:34-907,這個名字在daemon的整個生命周期是唯一的。但是這種名字總是臨時分配,無法確定的,也難以記憶,因此應用可以要求有另外一個名字well-known name 來對應這個唯一標識,就像我們使用域名來對應IP地址一樣。例如可以使用com.mycompany來映射:34-907。應用程序可能會要求擁有額外的周知名字(well-knownname )。例如,你可以寫一個規范來定義一個名字叫做 com.mycompany.TextEditor。你的協議可以指定自己擁有這個名字,一個應用程序應該在路徑/com/mycompany /TextFileManager下有一個支持接口org.freedesktop.FileHandler的對象。應用程序就可以發送消息到這個總線名字,對象,和接口以執行方法調用。

當一個應用結束或者崩潰是,OS kernel會關閉它的總線連接。總線發送notification消息告訴其他應用,這個應用的名字已經失去他的owner。當檢測到這類notification時,應用可以知道其他應用的生命周期。這種方式也可用於只有一個實例的應用,即不開啟同樣的兩個應用的情況。

 

地址

連接建立有server和client,對於bus daemon,應用就是client,daemon是server。一個D-Bus的地址是指server用於監聽,client用於連接的地方,例如unix:path=/tmp/abcedf標識server將在路徑/tmp/abcedf的UNIX domain socket監聽。地址可以是指定的TCP/IP socket或者其他在或者將在D-Bus協議中定義的傳輸方式。

  如果使用bus daemon,libdbus將通過讀取環境變量自動獲取session bus damon的地址,通過檢查一個指定的UNIX domain socket路徑獲取system bus的地址。如果使用D-bus,但不是daemon,需要定義那個應用是server,那個是client,並定義一套機制是他們認可server的地址,這不是通常的做法。

  通過上面的描述,我們可以獲得下面的視圖:

Address –> [BusName] –> Path –> Interface –> Method

bus name不是必要的,它只在daemon的情況下用於路由,點對點的直接連接是不需要的。

簡單地說:Address是D-Bus中server用來監聽client的地址,當一個client連接上D-Bus,通常是Daemo的方式,這個client就有了一個Bus Name。其他應用可以根據消息中所帶的Bus Name,來判斷和哪個應用相關。消息在總線中傳遞的時候,傳遞到應用中,再根據objectpath,送至應用中具體的對象實例中,也就是是應用中根據Interface創建的對象。這些Interface有method和singal兩種,用來發送、接收、響應消息。

 

一個例子的示意圖:

 

D-Bus 消息

消息通過D-Bus在進程間傳遞。有四類消息:

一、Method call消息:將觸發對象的一個method 

二、Method return消息:觸發的方法返回的結果

       三、Error消息:觸發的方法返回一個異常 

四、Signal消息:通知,可以看作為事件消息。

 

一個消息有消息頭header,里面有field,有一個消息體body,里面有參數arguments。消息頭包含消息體的路由信息,消息體就是凈荷payload。頭字段可能包括發送者的bus名,目的地的bus名,方法或者signal名等等,其中一個頭字段是用於描述body中的參數的類型,例如“i”標識32位整數,"ii”表示凈荷為2個32為整數。

 

發送Method call消息的場景

  一個method call消息從進程A到進程B,B將應答一個method return消息或者error消息。在每個call消息帶有一個序列號,應答消息也包含同樣的號碼,使之可以對應起來。他們的處理過程如下:

如果提供proxy,通過觸發本地一個對象的方法從而觸發另一個進程的遠端對象的方法。應用調用proxy的一個方法,proxy構造一個method call消息發送到遠端進程。

對於底層的API,不使用proxy,應用需要自己構造method call消息。

一個method call消息包含:遠端進程的bus name,方法名字,方法的參數,遠端進程中object path,可選的接口名字。

method call消息發送到bus daemon

bus daemon查看目的地的bus name。如果一個進程對應這個名字,bus daemon將method call消息發送到該進程中。如果沒有發現匹配,bus daemon創建一個error消息作為應答返回。

進程接收后將method call消息分拆。對於簡單的底層API情況,將立即執行方法,並發送一個method reply消息給bus daemon。對於高層的API,將檢查對象path,interface和method,觸發一個native object的方法,並將返回值封裝在一個method reply消息中。

bus daemon收到method reply消息,將其轉發到原來的進程中進程查看method reply消息,獲取返回值。這個響應也可以標識一個error的殘生。當使用高級的捆綁,method reply消息將轉換為proxy方法的返回值或者一個exception。

Bus daemon保證message的順序,不會亂序。例如我們發送兩個method call消息到同一個接受方,他們將按順序接受。接收方並不要求一定按順序回復。消息有一個序列號了匹配收發消息。

 

發送Signal的場景

  signal是個廣播的消息,不需要響應,接收方向daemon注冊匹配的條件,包括發送方和信號名,bus守護只將信號發送給希望接受的進程。處理流程如下:

一個signal消息發送到bus daemon。

signal消息包含發布該信號的interface名字,signal的名字,進程的bus名字,以及參數。

任何進程都可以注冊的匹配條件(match rules)表明它所感興趣的signal。總線有個注冊match rules列表。

bus daemon檢查那些進程對該信號有興趣,將信號消息發送到這些進程中。

收到信號的進程決定如何處理。如果使用高層的捆綁,一個porxy對象將會十分一個native的信號。如果使用底層的API,進程需要檢查信號的發送發和信號的名字決定如果進行處理。

 

Introspection

  D-Bus對象可能支持一個接口org.freedesktop.DBus.Introspectable。該接口有一個方法Introspect,不帶參數,將返回一個XML string。這個XML字符串描述接口,方法,信號。

D-Bus提供兩個命令dbus-monitor,可以查看bus,dbus-send命令,可以發送消息。

 

Signal的收發小例子

從底層,即libdbus學習如何發送signal,以及如何監聽signal。signal在D-Bus的Daemon中廣播,為了提高效率,只發送給向daemon注冊要求該singal的對象。

 

對於程序,第一步需要將應用和D-Bus后台建立連接,也就是和System D-Busdaemon或者Session D-Bus daemon建立連接。一旦建立,daemon會給這條連接分配一個名字,這個名字在system或者session的生命周期是唯一的,即unique connectionname,為了方便記憶,可以為這條連接分配一個便於記憶的well-known name。對於信號方式,分配這個名字不是必須的(在method_call中是需要的),因為在信號的監聽中秩序給出Interface的名字和信號名稱,在下面的例子中,可以將相關的代碼屏蔽掉,不影響運行,但是通常我們都這樣處理,尤其在復雜的程序中。在我們的例子中,定義這個BUS name為test.singal.source。當然一個好的名字,為了避免於其他應用重復,應當使用com.mycompany.myfunction之類的名字。 ,而interface的名字,一般前面和connection的BUS name一致。

 

發送方的小程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus.h>
#include <unistd.h>

int send_a_signal( char * sigvalue)
{
    DBusError err;
    DBusConnection * connection;
    DBusMessage * msg;
    DBusMessageIter arg;
    dbus_uint32_t  serial =0;
    int ret;

    //步驟1:建立與D-Bus后台的連接
    
    dbus_error_init(&err);
     
    connection =dbus_bus_get(DBUS_BUS_SESSION ,&err );
    if(dbus_error_is_set(&err)){
        fprintf(stderr,"ConnectionErr : %s\n",err.message);
        dbus_error_free(&err);
    }
    if(connection == NULL)
        return -1;

    //步驟2:給連接名分配一個well-known的名字作為Bus name,這個步驟不是必須的,可以用if 0來注釋着一段代碼,我們可以用這個名字來檢查,是否已經開啟了這個應用的另外的進程。
#if 1
    ret =dbus_bus_request_name(connection,"test.singal.source",DBUS_NAME_FLAG_REPLACE_EXISTING,&err);
    if(dbus_error_is_set(&err)){
        fprintf(stderr,"Name Err :%s\n",err.message);
        dbus_error_free(&err);
    }
    if(ret !=DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
        return -1;
#endif

    //步驟3:發送一個信號
    //根據圖,我們給出這個信號的路徑(即可以指向對象),接口,以及信號名,創建一個Message
    if((msg =dbus_message_new_signal("/test/signal/Object","test.signal.Type","Test"))== NULL){
        fprintf(stderr,"MessageNULL\n");
        return -1;
    }
    //給這個信號(messge)具體的內容
    dbus_message_iter_init_append(msg,&arg);
   if(!dbus_message_iter_append_basic(&arg,DBUS_TYPE_STRING,&sigvalue)){
        fprintf(stderr,"Out OfMemory!\n");
        return -1;
    }

    //步驟4: 將信號從連接中發送
    if( !dbus_connection_send(connection,msg,&serial)){
        fprintf(stderr,"Out of Memory!\n");
        return -1;
    }
    dbus_connection_flush(connection);
    printf("Signal Send\n");

   //步驟5: 釋放相關的分配的內存。
    dbus_message_unref(msg );
    return 0;
}
int main( int argc , char ** argv){
   send_a_signal("Hello,world!");
    return 0;
}


 

希望接收該信號的的小程序例子

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus.h>
#include <unistd.h>

void listen_signal()
{
    DBusMessage * msg;
    DBusMessageIter arg;
    DBusConnection * connection;
    DBusError err;
    int ret;
    char * sigvalue;

     //步驟1:建立與D-Bus后台的連接
    dbus_error_init(&err);
    connection =dbus_bus_get(DBUS_BUS_SESSION, &err);
    if(dbus_error_is_set(&err)){
        fprintf(stderr,"ConnectionError %s\n",err.message);
        dbus_error_free(&err);
    }
    if(connection == NULL)
        return;

   //步驟2:給連接名分配一個可記憶名字test.singal.dest作為Bus name,這個步驟不是必須的,但推薦這樣處理
    ret =dbus_bus_request_name(connection,"test.singal.dest",DBUS_NAME_FLAG_REPLACE_EXISTING,&err);
    if(dbus_error_is_set(&err)){
        fprintf(stderr,"Name Error%s\n",err.message);
        dbus_error_free(&err);
    }
    if(ret !=DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
        return;

    //步驟3:通知D-Bus daemon,希望監聽來行接口test.signal.Type的信號
    dbus_bus_add_match(connection,"type='signal',interface='test.signal.Type'",&err);
    //實際需要發送東西給daemon來通知希望監聽的內容,所以需要flush
    dbus_connection_flush(connection);
    if(dbus_error_is_set(&err)){
        fprintf(stderr,"Match Error%s\n",err.message);
        dbus_error_free(&err);
    }
   
    //步驟4:在循環中監聽,每隔開1秒,就去試圖自己的連接中獲取這個信號。這里給出的是中連接中獲取任何消息的方式,所以獲取后去檢查一下這個消息是否我們期望的信號,並獲取內容。我們也可以通過這個方式來獲取method call消息。
    while(1){
        dbus_connection_read_write(connection,0);
        msg =dbus_connection_pop_message (connection);
        if(msg == NULL){
            sleep(1);
            continue;
        }
   
        if(dbus_message_is_signal(msg,"test.signal.Type","Test")){
            if(!dbus_message_iter_init(msg,&arg))
                fprintf(stderr,"MessageHas no Param");
            else if(dbus_message_iter_get_arg_type(&arg)!= DBUS_TYPE_STRING)
                g_printerr("Param isnot string");
            else
                dbus_message_iter_get_basic(&arg,&sigvalue);
            printf("Got Singal withvalue : %s\n",sigvalue);
        }
        dbus_message_unref(msg);
    }//End of while
       
}

int main( int argc , char ** argv){
    listen_signal();
    return 0;
}


 

Method的收發小例子

監聽method和監聽signal的方式非常相似。在給出例子之前,我希望和上次學習一樣給出一個示意圖,更好地了解D-Bus的各個概念。

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus.h>
#include <unistd.h>

 
void reply_to_method_call(DBusMessage * msg, DBusConnection * conn){
    DBusMessage * reply;
    DBusMessageIter arg;
    char * param = NULL;
    dbus_bool_t stat = TRUE;
    dbus_uint32_t level = 2010;
    dbus_uint32_t serial = 0;
   
    //從msg中讀取參數,這個在上一次學習中學過
   if(!dbus_message_iter_init(msg,&arg))
        printf("Message has noargs\n");
    else if(dbus_message_iter_get_arg_type(&arg)!= DBUS_TYPE_STRING)
        printf("Arg is notstring!\n");
    else
       dbus_message_iter_get_basic(&arg,& param);
    if(param == NULL) return;


    //創建返回消息reply
    reply = dbus_message_new_method_return(msg);
    //在返回消息中填入兩個參數,和信號加入參數的方式是一樣的。這次我們將加入兩個參數。
    dbus_message_iter_init_append(reply,&arg);
    if(!dbus_message_iter_append_basic(&arg,DBUS_TYPE_BOOLEAN,&stat)){
        printf("Out ofMemory!\n");
        exit(1);
    }
    if(!dbus_message_iter_append_basic(&arg,DBUS_TYPE_UINT32,&level)){
        printf("Out ofMemory!\n");
        exit(1);
    }
  //發送返回消息
      if( !dbus_connection_send(conn, reply,&serial)){
        printf("Out of Memory\n");
        exit(1);
    }
    dbus_connection_flush (conn);
    dbus_message_unref (reply);
}

 
void listen_dbus()
{
    DBusMessage * msg;
    DBusMessageIter arg;
    DBusConnection * connection;
    DBusError err;
    int ret;
    char * sigvalue;

    dbus_error_init(&err);
    //創建於session D-Bus的連接
    connection =dbus_bus_get(DBUS_BUS_SESSION, &err);
    if(dbus_error_is_set(&err)){
        fprintf(stderr,"ConnectionError %s\n",err.message);
        dbus_error_free(&err);
    }
    if(connection == NULL)
        return;
    //設置一個BUS name:test.wei.dest
    ret =dbus_bus_request_name(connection,"test.wei.dest",DBUS_NAME_FLAG_REPLACE_EXISTING,&err);
    if(dbus_error_is_set(&err)){
        fprintf(stderr,"Name Error%s\n",err.message);
        dbus_error_free(&err);
    }
    if(ret !=DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
        return;

    //要求監聽某個singal:來自接口test.signal.Type的信號
   dbus_bus_add_match(connection,"type='signal',interface='test.signal.Type'",&err);
    dbus_connection_flush(connection);
    if(dbus_error_is_set(&err)){
        fprintf(stderr,"Match Error%s\n",err.message);
        dbus_error_free(&err);
    }

    while(true){
        dbus_connection_read_write(connection,0);
        msg =dbus_connection_pop_message (connection);

        if(msg == NULL){
            sleep(1);
            continue;
        }

        if(dbus_message_is_signal(msg,"test.signal.Type","Test")){
            if(!dbus_message_iter_init(msg,&arg))
               fprintf(stderr,"Message Has no Param");
            elseif(dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_STRING)
                g_printerr("Param isnot string");
            else
               dbus_message_iter_get_basic(&arg,&sigvalue);
        }else if(dbus_message_is_method_call(msg,"test.method.Type","Method")){
            //我們這里面先比較了接口名字和方法名字,實際上應當現比較路徑
            if(strcmp(dbus_message_get_path(msg),"/test/method/Object") == NULL)
               reply_to_method_call(msg,connection);
        }
        dbus_message_unref(msg);
    }
   
   
}
int main( int argc , char ** argv){
    listen_dbus();
    return 0;
}


 

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus.h>
#include <unistd.h>
//建立與session D-Bus daemo的連接,並設定連接的名字,相關的代碼已經多次使用過了
DBusConnection * connect_dbus(){
    DBusError err;
    DBusConnection * connection;
    int ret;

    //Step 1: connecting session bus
     
    dbus_error_init(&err);
     
    connection =dbus_bus_get(DBUS_BUS_SESSION, &err);
    if(dbus_error_is_set(&err)){
        fprintf(stderr,"ConnectionErr : %s\n",err.message);
        dbus_error_free(&err);
    }
    if(connection == NULL)
        return NULL;

    //step 2: 設置BUS name,也即連接的名字。
    ret =dbus_bus_request_name(connection,"test.wei.source",DBUS_NAME_FLAG_REPLACE_EXISTING,&err);
    if(dbus_error_is_set(&err)){
        fprintf(stderr,"Name Err :%s\n",err.message);
        dbus_error_free(&err);
    }
    if(ret !=DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
        return NULL;

    return connection;   
}

void send_a_method_call(DBusConnection * connection,char * param)
{
   DBusError err;
    DBusMessage * msg;
    DBusMessageIter    arg;
    DBusPendingCall * pending;
    dbus_bool_t * stat;
    dbus_uint32_t * level;   
   
    dbus_error_init(&err);

    //針對目的地地址,請參考圖,創建一個method call消息。Constructs a new message to invoke a method on a remote object.
    msg =dbus_message_new_method_call ("test.wei.dest","/test/method/Object","test.method.Type","Method");
   if(msg == NULL){
        g_printerr("MessageNULL");
        return;
    }

    //為消息添加參數。Appendarguments
    dbus_message_iter_init_append(msg, &arg);
    if(!dbus_message_iter_append_basic(&arg, DBUS_TYPE_STRING,¶m)){
       g_printerr("Out of Memory!");
        exit(1);
    }

    //發送消息並獲得reply的handle。Queues amessage to send, as withdbus_connection_send() , but also returns aDBusPendingCall used to receive a reply to the message.
    if(!dbus_connection_send_with_reply (connection, msg,&pending, -1)){
       g_printerr("Out of Memory!");
        exit(1);
    }     

    if(pending == NULL){
        g_printerr("Pending CallNULL: connection is disconnected ");
        dbus_message_unref(msg);
        return;
    }

    dbus_connection_flush(connection);
    dbus_message_unref(msg);
 
   //waiting a reply,在發送的時候,已經獲取了methodreply的handle,類型為DBusPendingCall。
    // block until we recieve a reply, Block until the pendingcall is completed.
   dbus_pending_call_block (pending);
    //get the reply message,Gets thereply, or returns NULL if none has been received yet.
    msg =dbus_pending_call_steal_reply (pending);
    if (msg == NULL) {
        fprintf(stderr, "ReplyNull\n");
         exit(1);
    }
     // free the pendingmessage handle
     dbus_pending_call_unref(pending);
    // read the parameters
    if(!dbus_message_iter_init(msg, &arg))
        fprintf(stderr, "Message hasno arguments!\n");
    else if (dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_BOOLEAN)
        fprintf(stderr, "Argument isnot boolean!\n");
    else
        dbus_message_iter_get_basic(&arg, &stat);
 
    if (!dbus_message_iter_next(&arg))
        fprintf(stderr, "Message hastoo few arguments!\n");
    else if (dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_UINT32 )
        fprintf(stderr, "Argument isnot int!\n");
    else
        dbus_message_iter_get_basic(&arg, &level);

    printf("Got Reply: %d,%d\n", stat, level);
    dbus_message_unref(msg);
}

int main( int argc , char ** argv){
   DBusConnection * connection;
    connection = connect_dbus();
    if(connection == NULL)
        return -1;

   send_a_method_call(connection,"Hello, D-Bus");
    return 0;
}

 



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM