和菜鸟一起学linux之DBUS基础学习记录

转自:http://blog.csdn.net/eastmoon502136/article/details/10044993

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一致。

 

发送方的小程序

[html] view plaincopy
  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.   
  8. int send_a_signal( char * sigvalue)  
  9. {  
  10.     DBusError err;  
  11.     DBusConnection * connection;  
  12.     DBusMessage * msg;  
  13.     DBusMessageIter arg;  
  14.     dbus_uint32_t  serial =0;  
  15.     int ret;  
  16.   
  17.     //步骤1:建立与D-Bus后台的连接  
  18.       
  19.     dbus_error_init(&err);  
  20.        
  21.     connection =dbus_bus_get(DBUS_BUS_SESSION ,&err );  
  22.     if(dbus_error_is_set(&err)){  
  23.         fprintf(stderr,"ConnectionErr : %s\n",err.message);  
  24.         dbus_error_free(&err);  
  25.     }  
  26.     if(connection == NULL)  
  27.         return -1;  
  28.   
  29.     //步骤2:给连接名分配一个well-known的名字作为Bus name,这个步骤不是必须的,可以用if 0来注释着一段代码,我们可以用这个名字来检查,是否已经开启了这个应用的另外的进程。  
  30. #if 1  
  31.     ret =dbus_bus_request_name(connection,"test.singal.source",DBUS_NAME_FLAG_REPLACE_EXISTING,&err);  
  32.     if(dbus_error_is_set(&err)){  
  33.         fprintf(stderr,"Name Err :%s\n",err.message);  
  34.         dbus_error_free(&err);  
  35.     }  
  36.     if(ret !=DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)  
  37.         return -1;  
  38. #endif  
  39.   
  40.     //步骤3:发送一个信号  
  41.     //根据图,我们给出这个信号的路径(即可以指向对象),接口,以及信号名,创建一个Message  
  42.     if((msg =dbus_message_new_signal("/test/signal/Object","test.signal.Type","Test"))== NULL){  
  43.         fprintf(stderr,"MessageNULL\n");  
  44.         return -1;  
  45.     }  
  46.     //给这个信号(messge)具体的内容  
  47.     dbus_message_iter_init_append(msg,&arg);  
  48.    if(!dbus_message_iter_append_basic(&arg,DBUS_TYPE_STRING,&sigvalue)){  
  49.         fprintf(stderr,"Out OfMemory!\n");  
  50.         return -1;  
  51.     }  
  52.   
  53.     //步骤4: 将信号从连接中发送  
  54.     if( !dbus_connection_send(connection,msg,&serial)){  
  55.         fprintf(stderr,"Out of Memory!\n");  
  56.         return -1;  
  57.     }  
  58.     dbus_connection_flush(connection);  
  59.     printf("Signal Send\n");  
  60.   
  61.    //步骤5: 释放相关的分配的内存。  
  62.     dbus_message_unref(msg );  
  63.     return 0;  
  64. }  
  65. int main( int argc , char ** argv){  
  66.    send_a_signal("Hello,world!");  
  67.     return 0;  
  68. }  


 

希望接收该信号的的小程序例子

[html] view plaincopy
  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.   
  8. void listen_signal()  
  9. {  
  10.     DBusMessage * msg;  
  11.     DBusMessageIter arg;  
  12.     DBusConnection * connection;  
  13.     DBusError err;  
  14.     int ret;  
  15.     char * sigvalue;  
  16.   
  17.      //步骤1:建立与D-Bus后台的连接  
  18.     dbus_error_init(&err);  
  19.     connection =dbus_bus_get(DBUS_BUS_SESSION, &err);  
  20.     if(dbus_error_is_set(&err)){  
  21.         fprintf(stderr,"ConnectionError %s\n",err.message);  
  22.         dbus_error_free(&err);  
  23.     }  
  24.     if(connection == NULL)  
  25.         return;  
  26.   
  27.    //步骤2:给连接名分配一个可记忆名字test.singal.dest作为Bus name,这个步骤不是必须的,但推荐这样处理  
  28.     ret =dbus_bus_request_name(connection,"test.singal.dest",DBUS_NAME_FLAG_REPLACE_EXISTING,&err);  
  29.     if(dbus_error_is_set(&err)){  
  30.         fprintf(stderr,"Name Error%s\n",err.message);  
  31.         dbus_error_free(&err);  
  32.     }  
  33.     if(ret !=DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)  
  34.         return;  
  35.   
  36.     //步骤3:通知D-Bus daemon,希望监听来行接口test.signal.Type的信号  
  37.     dbus_bus_add_match(connection,"type='signal',interface='test.signal.Type'",&err);  
  38.     //实际需要发送东西给daemon来通知希望监听的内容,所以需要flush  
  39.     dbus_connection_flush(connection);  
  40.     if(dbus_error_is_set(&err)){  
  41.         fprintf(stderr,"Match Error%s\n",err.message);  
  42.         dbus_error_free(&err);  
  43.     }  
  44.      
  45.     //步骤4:在循环中监听,每隔开1秒,就去试图自己的连接中获取这个信号。这里给出的是中连接中获取任何消息的方式,所以获取后去检查一下这个消息是否我们期望的信号,并获取内容。我们也可以通过这个方式来获取method call消息。  
  46.     while(1){  
  47.         dbus_connection_read_write(connection,0);  
  48.         msg =dbus_connection_pop_message (connection);  
  49.         if(msg == NULL){  
  50.             sleep(1);  
  51.             continue;  
  52.         }  
  53.      
  54.         if(dbus_message_is_signal(msg,"test.signal.Type","Test")){  
  55.             if(!dbus_message_iter_init(msg,&arg))  
  56.                 fprintf(stderr,"MessageHas no Param");  
  57.             else if(dbus_message_iter_get_arg_type(&arg)!= DBUS_TYPE_STRING)  
  58.                 g_printerr("Param isnot string");  
  59.             else  
  60.                 dbus_message_iter_get_basic(&arg,&sigvalue);  
  61.             printf("Got Singal withvalue : %s\n",sigvalue);  
  62.         }  
  63.         dbus_message_unref(msg);  
  64.     }//End of while  
  65.          
  66. }  
  67.   
  68. int main( int argc , char ** argv){  
  69.     listen_signal();  
  70.     return 0;  
  71. }  


 

Method的收发小例子

监听method和监听signal的方式非常相似。在给出例子之前,我希望和上次学习一样给出一个示意图,更好地了解D-Bus的各个概念。

 

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


 

 

[html] view plaincopy
  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. //建立与session D-Bus daemo的连接,并设定连接的名字,相关的代码已经多次使用过了  
  8. DBusConnection * connect_dbus(){  
  9.     DBusError err;  
  10.     DBusConnection * connection;  
  11.     int ret;  
  12.   
  13.     //Step 1: connecting session bus  
  14.        
  15.     dbus_error_init(&err);  
  16.        
  17.     connection =dbus_bus_get(DBUS_BUS_SESSION, &err);  
  18.     if(dbus_error_is_set(&err)){  
  19.         fprintf(stderr,"ConnectionErr : %s\n",err.message);  
  20.         dbus_error_free(&err);  
  21.     }  
  22.     if(connection == NULL)  
  23.         return NULL;  
  24.   
  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\n",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.   
  48.     //针对目的地地址,请参考图,创建一个method call消息。Constructs a new message to invoke a method on a remote object.  
  49.     msg =dbus_message_new_method_call ("test.wei.dest","/test/method/Object","test.method.Type","Method");  
  50.    if(msg == NULL){  
  51.         g_printerr("MessageNULL");  
  52.         return;  
  53.     }  
  54.   
  55.     //为消息添加参数。Appendarguments  
  56.     dbus_message_iter_init_append(msg, &arg);  
  57.     if(!dbus_message_iter_append_basic(&arg, DBUS_TYPE_STRING,¶m)){  
  58.        g_printerr("Out of Memory!");  
  59.         exit(1);  
  60.     }  
  61.   
  62.     //发送消息并获得reply的handle。Queues amessage to send, as withdbus_connection_send() , but also returns aDBusPendingCall used to receive a reply to the message.  
  63.     if(!dbus_connection_send_with_reply (connection, msg,&pending, -1)){  
  64.        g_printerr("Out of Memory!");  
  65.         exit(1);  
  66.     }       
  67.   
  68.     if(pending == NULL){  
  69.         g_printerr("Pending CallNULL: connection is disconnected ");  
  70.         dbus_message_unref(msg);  
  71.         return;  
  72.     }  
  73.   
  74.     dbus_connection_flush(connection);  
  75.     dbus_message_unref(msg);  
  76.    
  77.    //waiting a reply,在发送的时候,已经获取了methodreply的handle,类型为DBusPendingCall。  
  78.     // block until we recieve a reply, Block until the pendingcall is completed.  
  79.    dbus_pending_call_block (pending);  
  80.     //get the reply message,Gets thereply, or returns NULL if none has been received yet.  
  81.     msg =dbus_pending_call_steal_reply (pending);  
  82.     if (msg == NULL) {  
  83.         fprintf(stderr, "ReplyNull\n");  
  84.          exit(1);  
  85.     }  
  86.      // free the pendingmessage handle  
  87.      dbus_pending_call_unref(pending);  
  88.     // read the parameters  
  89.     if(!dbus_message_iter_init(msg, &arg))  
  90.         fprintf(stderr, "Message hasno arguments!\n");  
  91.     else if (dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_BOOLEAN)  
  92.         fprintf(stderr, "Argument isnot boolean!\n");  
  93.     else  
  94.         dbus_message_iter_get_basic(&arg, &stat);  
  95.    
  96.     if (!dbus_message_iter_next(&arg))  
  97.         fprintf(stderr, "Message hastoo few arguments!\n");  
  98.     else if (dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_UINT32 )  
  99.         fprintf(stderr, "Argument isnot int!\n");  
  100.     else  
  101.         dbus_message_iter_get_basic(&arg, &level);  
  102.   
  103.     printf("Got Reply: %d,%d\n", stat, level);  
  104.     dbus_message_unref(msg);  
  105. }  
  106.   
  107. int main( int argc , char ** argv){  
  108.    DBusConnection * connection;  
  109.     connection = connect_dbus();  
  110.     if(connection == NULL)  
  111.         return -1;  
  112.   
  113.    send_a_method_call(connection,"Hello, D-Bus");  
  114.     return 0;  
  115. }  
  116.  



另:编译时命令 gcc -o signal_send signal_send.c `pkg-config --cflags --libs dbus-glib-1`

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/274083.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 第二十课 广播机制(大喇叭)----发送自定义广播(包括发送标准广播和发送有序广播)

广播分为两种类型&#xff1a;标准广播和有序广播 我们来看一下具体这两者的具体区别&#xff1a; 1、发送标准广播 我们需要先定义一个广播接收器来准备接收此广播才行&#xff0c;否则也是白发。 新建一个MyBroadcastReceiver,代码如下&#xff1a; package com.example.broa…

八大排序算法

概述 排序有内部排序和外部排序&#xff0c;内部排序是数据记录在内存中进行排序&#xff0c;而外部排序是因排序的数据很大&#xff0c;一次不能容纳全部的排序记录&#xff0c;在排序过程中需要访问外存。 我们这里说说八大排序就是内部排序。 当n较大&#xff0c;则应采用…

Android 第二十一课 RecyclerView简单的应用之编写“精美”的聊天页面

1、由于我们会使用到RecyclerView&#xff0c;因此首先需要在app/build.gradle当中添加依赖库。如下&#xff1a; apply plugin: com.android.application .... dependencies {....compile com.android.support:recyclerview-v7:26.1.0 } 2、然后开始编写主页面&#xff0c;修该…

JavaScript 第四课 案例研究:JavaScript图片库

主要内容&#xff1a;编写一个优秀的标记文件编写一个JavaScript函数以显示用户想要查看的内容由标记出发函数调用使用几个新方法扩展这个JavaScript函数 学习过DOM&#xff0c;我们用JavaScript和DOM去建立一个图片库。最好的办法是什么呢&#xff1f; 利用JavaScript来建立图…

windows下mongodb安装与使用整理

一、首先安装mongodb 1.下载地址&#xff1a;http://www.mongodb.org/downloads 2.解压缩到自己想要安装的目录&#xff0c;比如d:\mongodb 3.创建文件夹d:\mongodb\data\db、d:\mongodb\data\log&#xff0c;分别用来安装db和日志文件&#xff0c;在log文件夹下创建一个日志文…

USACO4.12Beef McNuggets(背包+数论)

昨天晚上写的一题 结果USACO一直挂中 今天交了下 有一点点的数论知识 背包很好想 就是不好确定上界 官方题解&#xff1a; 这是一个背包问题。一般使用动态规划求解。 一种具体的实现是&#xff1a;用一个线性表储存所有的节点是否可以相加得到的状态&#xff0c;然后每次可以…

Java 循环语句中 break,continue,return有什么区别?

break 结束循环&#xff0c;跳出循环体,进行后面的程序;continue 结束本次循环&#xff0c;进行下次循环;return 跳出循环体所在的方法&#xff0c;相当于结束该方法; 例子&#xff1a; public class whiletrueTest{public static void main(String[] args) {heihei();haha();…

运算放大器单电源应用中的使用齐纳二极管偏置方法

运算放大器单电源应用中的偏置方法除了使用大电阻使运放输出达到电源电压的一半外&#xff0c;还有使用齐纳二极管&#xff08;稳压管&#xff09;方法也能得到达到应用目的。 下面就推荐几个齐纳二极管&#xff08;分别对应着电源电压是15V,12V&#xff0c;9V;5V&#xff09; …

dpi 、 dip 、分辨率、屏幕尺寸、px、density 关系以及换算

本文转自&#xff1a;http://www.cnblogs.com/yaozhongxiao/archive/2014/07/14/3842908.html 一、基本概念 dip &#xff1a; Density independent pixels &#xff0c;设备无关像素。 dp &#xff1a;就是dip px &#xff1a; 像素 dpi &#xf…

Java 集合中关于Iterator 和ListIterator的详解

1.Iterator Iterator的定义如下&#xff1a;public interface Iterator<E> {}Iterator是一个接口&#xff0c;它是集合的迭代器。集合可以通过Iterator去遍历集合中的元素。Iterator提供的API接口如下&#xff1a;forEachRemaining(Consumer<? super E> action)&a…

使用xrandr和cvt命令添加自定义的分辨率模式

可以使用xrandr -q命令查看当前支持的分辨率模式: 如果过没有你想要的分辨率模式,则需要自己创建新的分辨率模式,例如,我想要创建800x750的分辨率模式,步骤如下: 1.使用cvt命令创建新的分辨率: 2.使用xrandr –newmode modeline信息(CVT命令产生的结果)创建新的mode: $xra…

Java List集合

我们先看一下jdk1.9对其的描述&#xff1a;什么是List&#xff0c;也就是一个有序集合(序列)。1.List接口 List集合代表一个有序集合&#xff0c;集合中每个元素都有其对应的顺序索引。List集合允许使用重复元素&#xff0c;可以通过索引来访问指定位置的集合元素。 List接口继…

Java Set集合

Set接口什么是Set&#xff0c;就是不包含重复元素的集合。Set是一种不包括重复元素的Collection。它维持它自己的内部排序&#xff0c;所以随机访问没有任何意义。与List一样&#xff0c;它同样允许null的存在但是仅有一个。由于Set接口的特殊性&#xff0c;所有传入Set集合中的…

Java Map集合

Map集合&#xff1a;Map接口Map与List、Set接口不同&#xff0c;它是由一系列键值对组成的集合&#xff0c;提供了key到Value的映射。同时它也没有继承Collection。在Map中它保证了key与value之间的一一对应关系。也就是说一个key对应一个value&#xff0c;所以它不能存在相同的…

gsettings命令使用简介

1.gsettings创建项 应用程序可以使用gsettings来保存配置信息&#xff0c;可以通过代码在程序中进行设置、修改gsettings的已有的项&#xff0c;但是不能通过程序代码创建新的gsettings项&#xff0c;gsettings的项的在一个叫做schema的规范文件中创建&#xff0c;schema文档其…

Java 之HashSet、LinkedHashSet、TreeSet比较

4.HashSet、LinkedHashSet、TreeSet比较 Set接口Set不允许包含相同的元素&#xff0c;如果试图把两个相同元素加入同一个集合中&#xff0c;add方法返回false。Set判断两个对象相同不是使用运算符&#xff0c;而是根据equals方法。也就是说&#xff0c;只要两个对象用equals方法…

jquery1.9学习笔记 之选择器(基本元素四)

ID选择器("#id") 描述&#xff1a; 选择与给出ID属性匹配的单元标签。 对于ID选择器&#xff0c;jquery使用JS的函数document.getElementById()&#xff0c;当一个标签附加到ID选择器上时&#xff0c;也是非常有效的。如h2#pageTitle&#xff0c;jquery会在识别元素标…

Java(ArrayList和LinkedList)、(HashTable与HashMap)、(HashMap、Hashtable、LinkedHashMap和TreeMap比较)

1.ArrayList和LinkedList &#xff08;1&#xff09;ArrayList是实现了基于动态数组的数据结构&#xff0c;LinkedList基于链表的数据结构。 &#xff08;2&#xff09;对于随机访问get和set&#xff0c;ArrayList绝对优于LinkedList&#xff0c;因为LinkedList要移动指针。 &a…

Java 集合之自动打包和解包以及泛型

自动打包与解包&#xff1a;泛型&#xff1a;上栗子&#xff1a; TestMap1.java: package com.zhj.www; import java.util.*;public class TestMap {public static void main(String[] args) {Map m1 new HashMap();Map m2 new TreeMap();//m1.put("one", new Inte…

泗洪高薪行业

泗洪高薪行业转载于:https://www.cnblogs.com/soundcode/p/3302297.html