当前位置: 首页 > Linux

【DBUS】认识GDBUS

时间:2023-04-06 23:51:08 Linux

DBUS什么是DBUSBUS是一种进程间通信(IPC)机制,支持进程间一对一和多对多通信。系统启动时,会同时启动一个后台服务进程(dbus-daemon)。当两个进程之间传递消息时,进程A会先将消息传递给dbus-daemon,然后dbus-daemon再将消息转发给目标进程。DBUS的类型最底层的dbus库就是libdbus。使用起来比较麻烦。同时,也有基于特定框架(Qt、Glib、Python、C#、Ruby、Java等)的dbus编程框架的实现,有的依赖libdbus,有的基于dbus重新实现规格在dbus官网可以找到DBUS的应用,可以找到使用dbus的项目。例如Android中使用的Wi-Fi管理配置工具wpa_supplicant,Linux中的蓝牙协议栈BlueZ,都使用了dbus通信框架。DBUS中的几个基本概念以下内容摘自《D-Bus Tutorial》。对于刚接触dbus的同学,建议先看这篇文章。Object和ObjectPath熟悉OO的同学可能更理解Object的概念。在Java和CPP中,Object显示为类的实例。简单地说,狗和人可以称为一个对象。对象有自己的状态和行为。例如:对象人体状态名称:二狗性别:男身高:1.2米行为吃、睡、打豆豆这些对象和行为在编程语言中称为Method和Property。在libdbus中,有一个概念NativeObject,但是忽略了这些NativeObject,而是使用了一个ObjectPath的概念。在高级应用程序编程中创建用于通信的对象时,会指定一个ObjectPath用于在dbus的较低级别路由消息。ObjectPath/org/bluez/dev_00_11_22_33_44_55/com/company/department/kafka的命名很像Java中package的概念。Method和Signal方法是一个有输入输出参数的函数,信号用于广播。如果一个对象需要得到这个信号,它需要先监听这个信号(watch)。信号也可以包含有用的信息。D-BUS中有四种消息:方法调用(methodcalls)方法返回(methodreturns)信号(signals)错误(errors)。要执行D-BUS对象的方法,您需要向该对象发送方法调用消息。它会完成一些处理(即执行对象中的Method,Method可以有输入参数。)并返回,返回消息或错误信息。信号的不同之处在于它们不返回任何内容:既不返回“信号返回”消息,也不返回任何类型的错误消息。接口接口是方法和信号的组合。每个对象可以包含一个或多个接口。接口命名方式:com.module.bluetooth.scan、org.freedesktop.Introspectable。Proxy在调用远程对象的方法时,可以在本地创建一个代理对象,这样就可以像调用本地对象一样调用远程对象。BusName当一个应用程序连接到总线上时,总线会给他分配一个唯一的总线名称(uniqueconnectname),它以:开头。同时,应用也会给他分配一个名字(well-knownname)。例如,当应用程序生命周期结束或崩溃时,“com.alkaid.TextEditor”总线名称将有另一个用途。Kernel会向其他应用程序发送通知,通知一个应用程序的生命周期已经结束。Address地址是server用来监听,client用来连接的地方。对于总线守护进程,它是服务器,应用程序是客户端。对于libdbus,通过查看环境变量获取sessiondbus-daemon的地址;通过检查特定的unix套接字域来获取系统dbus-daemon的地址。如果你使用了dbus,但是没有使用dbus-daemon,那你就得自己定义server和client,还需要定义一套方法来识别server和client。这个不常用。通过上面的描述,我们可以得到如下视图:当Client连接到bus-daemon时,它也有一个bus-name,应用程序为它分配了一个众所周知的名字,而bus-daemon为它分配了一个唯一的名字.消息投递时,会根据ObjectPath发送给对应的对象实例。MethodCall的使用场景AMethod消息从进程A发送给进程B,进程B会返回一个Method消息或Error消息。进程A的消息包含唯一的序号,进程B返回的消息也包含相同的序号。如果使用代理方法,通过调用本地代理对象的方法,代理构造一个对象发送给远端,触发远端对象的方法。Signal应用场景Signal是一种广播消息,不需要响应。总线守护进程只会将信号转发给所需的对象。所以接收方需要在bus-daemon中注册match-rules,包括发送方的名字和信号的名字,然后接收对应的信号。信号处理流程如下:向bus-daemon发送信号,信号包括bus-name、signalname、intfname和payload。接收者需要注册match-rules,match-rules用来告诉bus-daemon哪些是我感兴趣的信号,然后bus-daemon转发它们。对于receiver,如果使用libdbus,他会检查bus-name和signal,然后决定如何处理;如果使用绑定,绑定将在代理对象上发送本机信号。Introspectiondbus提供了一个方法org.freedesktop.DBus.Introspectable.Introspect,调用这个方法会返回一个XML字符串,可以用来查询具体对象支持的方法名。但是,查询的方法只是对象在理论上支持,并没有实际实现。GDbus编程实例dbus框架有很多。最近在学习蓝牙协议栈blueZ,用到了GDbus。这个例子也使用了这个框架。第一次使用需要安装相应的库。可以参考本文下面的案例,调用org.freedesktop的.DBus.ListActivatableNames方法返回所有可以在dbus-daemon上激活的服务名。#include#include#include#include#include#include#include#defineLOG(fmt,args...)printf(fmt,##args);intmain(void){DBusError错误;DBusConnection*dbus_conn;DBusMessage*消息;intret=0;诠释我=0;DBusMessageIterIter,subIter;字符*arr;DBusPendingCall*挂起;dbus_error_init(&err);dbus_conn=dbus_bus_get(DBUS_BUS_SYSTEM,&err);if(dbus_error_is_set(&err)){日志(err.message);返回-1;}if(NULL==dbus_conn){日志("-2");返回-2;}/*//你将在/etc/dbus-1/system.d/*.conf中创建.confret=dbus_bus_request_name(dbus_conn,"test.dbus.methodcall",DBUS_NAME_FLAG_REPLACE_EXISTING,&err);if(dbus_error_is_set(&err)){日志("%s\n",err.message);返回-3;}如果(DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER!=ret){LOG("-4\n");返回-4;}*///该方法没有入参,所以我们不需要加入入参message=dbus_message_new_method_call("org.freedesktop.DBus","/","org.freedesktop.DBus","ListActivatableNames");dbus_connection_send_with_reply(dbus_conn,消息,&pending,-1);dbus_connection_flush(dbus_conn);dbus_message_unref(消息);//阻塞在这里,直到调用完成,如果上面设置超时,超时也会返回dbus_pending_call_block(pending);//获取回复消息message=dbus_pending_call_steal_reply(pending);if(!dbus_message_iter_init(message,&Iter)){LOG("-6\n");}LOG("输入'%c'\n",dbus_message_iter_get_arg_type(&Iter));dbus_message_iter_recurse(&Iter,&subIter);//因为该方法返回的是数组String,所以需要将Iter中的数据迭代到subIter,然后get_basicLOG("type'%c'\n",dbus_message_iter_get_arg_type(&subIter));for(i=0;i<49;i++){dbus_message_iter_get_basic(&subIter,&arr);dbus_message_iter_next(&subIter);//指向下一个LOG("%s\n",arr);}printf("你好世界\n");}。