当前位置: 首页 > Linux

D-Bus教程

时间:2023-04-06 18:22:32 Linux

D-Bus教程什么是D-Bus?D-Bus是一个用于进程间通信的系统。在架构上分为三部分:一个libdbus库,允许两个app连接和交换信息,以及一个基于libdbus的daemon,各种app可以连接到daemon。守护进程将信息从一个应用程序路由到其他应用程序。基于应用程序框架的包库或绑定。例如,libdbus-glib和libdebus-qt。还有针对Python等语言的绑定。大多数开发人员直接使用这些包装库,它们声明了与Dbus相关的编程细节。libdbus作为底层后台支持上层绑定。libdbus的很多API只对绑定的实现有效。libdbus只支持一对一的连接,就像rawsockets一样,不同的是发送的不是字节流(bytestreams),而是消息。消息包括消息头和消息体,消息头表示信息的类型,消息体包含消息体的内容。Libdbus还可以允许实施特定的传输通道来完成应用程序细节,例如身份验证。消息总线守护进程为所有连接到D-bus的程序形成了一个轮状的集线器。车轮上的每个辐条都是基于libdbus的一对一连接,连接一个app。应用通过spoke向守护进程发送消息,守护进程在合适的时间将消息转发给其他连接的应用。daemon可以理解为路由器。系统中有多个总线守护进程实例。例如,世界上唯一的实例,像sendmail或Apache这样的系统守护进程,对于进程间通信接收什么样的消息有非常严格的安全要求(系统总线?)。其他守护进程实例在用户登录时创建,用于用户会话中应用程序之间的通信。系统级守护进程和每用户守护进程是分开的。会话中的IPC不会影响系统级消息总线,反之亦然。D-Bus应用程序有许多技术用于实现IPC或网络信息传输,例如:CORBA、DCE、DCOM、DCOP、XML-RPC、SOAP、MBUS、InternetCommunicationsEngine(ICE)。每个都是为特定类型的应用程序量身定制的。Dbus是为两种情况而生的:同一个桌面session中app之间的信息传递,这样session就被认为是一个整体,解决了进程生命周期的问题。桌面会话与操作系统之间的信息传递,即会话与内核或其他系统守护进程之间的通信。ConceptsNativeObjectsandObjectPaths开发者在自己的编程框架中定义对象,通常是基于一个基础类,比如java.lang.Object、GObject、QObject、python的baseObject等等。我们称之为本机对象。dbus协议和libdbus中的API并不关心nativeobject是如何定义的,而是提供了objectpath的概念。通过对象路径,上层绑定可以命名本机对象实例并允许远程应用程序引用这些对象。对象路径就像文件系统中的文件路径。例如,一个对象可以命名为/org/kde/kspread/sheets/3/cells/4/5。易于理解的路径很棒,但如果需要,您也可以命名为/com/mycompany/c5yo817y0c1y1c5b。在名称中指定命名空间是明智的,例如将路径的开头设置为您开发的域名。这样可以确保同一进程中的不同模块不会相互干扰。方法和信号每个对象都有成员(members),成员分为方法(methods)和信号(signals)。方法是对象可以调用的一组操作,带有输入或输出参数。信号被广播给任何对该信号感兴趣的人;信号也可以携带数据。引用方法或信号是通过它们的名称,例如Frobate或OnClickedInterfaces一个对象只是一个或多个接口。一个接口包含一组方法和信号(methodsandsignals),这个概念就像GLib或Qt或Java中的方法和信号。接口定义了对象实例的类型。dbus使用简单的命名空间字符串标识接口,例如org.freedesktop.Introspectable;大多数绑定会将这些接口直接映射到相应的编程语言结构,例如Java接口或C++纯虚拟类。Proxies代理(proxy)对象是一个本地对象,用来代表其他进程中的远程对象。底层DBusAPI创建方法调用、发送、接收和处理这些回复消息。proxy可以看成是一个普通的native对象,但是当你调用proxy中的方法时,bindings将操作转化为dbus方法调用消息,等待远程回复消息,解包返回值,返回给native方法...这是一个没有代理的伪代码示例:Messagemessage=newMessage("/remote/object/path","MethodName",arg1,arg2);连接connection=getBusConnection();connection.send(消息);消息回复=connection.waitForReply(message);if(reply.isError()){}else{对象returnValue=reply.getReturnValue();}使用代理Proxyproxy=newProxy(getBusConnection(),"/remote/object/path");ObjectreturnValue=proxy.MethodName(arg1,arg2);总线名称每当应用程序连接到dbus守护程序时,守护程序都会为应用程序分配一个唯一的连接名称,以冒号开头。总线名称始终指向同一个应用程序,不会重复使用。示例:34-907。冒号后面的数字除了唯一性外没有任何意义。应用程序还可以请求人类可读的名称。例如,com.mycompany.TextEditor。对应对象的路径可以是/com/mycompany/TextFileManager,接口是org.freedesktop.FileHandler,34-907(唯一名称)可以看作是一个IP地址,com.mycompany.TextEditor可以看作是一个域名。com.mycompany.TextEditor映射:34-907就像通信mycompany.com被映射到192.168.0.5。除了路由消息外,总线名称还可用于跟踪应用程序生命周期。当一个应用程序退出或崩溃时,操作系统内核会断开消息总线,然后消息总线发送消息通知其他应用程序该名称已失去其所有者。通过跟踪这些通知,您可以监控其他应用程序的生命周期。Bus名称还可以检测应用是否已经启动,可以用来实现单实例启动器。Addresses作为dbus的服务端或客户端,服务端监听来自客户端的连接,客户端连接服务端。一旦建立连接,它就是一个对称的消息流。Dbus地址表示服务器监听的位置和客户端连接的位置。例如,地址unix:path=/tmp/abcdef表示服务端会监听一个Unixsocket,路径为/tmp/abcdef,客户端会连接到这个socket。地址还可以指定TCP/IP套接字或其他类型的传输。BigConceptualPicture结合以上概念得到如下流程:Address->[BusName]->Path->Interface->MethodMessageDbus通过在两个进程之间发送消息来工作。不直接处理消息。四种消息:方法调用消息,用于调用对象的方法消息返回消息,返回方法处理结果的错误消息,返回方法调用中的异常信号消息,通知指定的对象信号被触发,可以理解为一个事件触发方法调用消息对应消息返回消息或者错误消息。每条消息都有一个消息头,包括字段、正文和桉树。Header可以看作是消息的路由信息??,Body可以看作是消息体。标头可能包含以下信息:发送方总线名称、目标总线名称、要调用的方法或信号等。标头中有一个字段描述正文中值的类型。例如字母i表示一个32位整数,ii表示body有两个32位整数。调用一个方法一个方法调用(methodcall)由两条消息组成。一个方法调用消息从进程A发送到进程B,相应的方法返回消息从进程B发送到进程A。发送和返回消息都必须经过总线守护进程路由。每条呼叫消息都包含一个唯一的号码,回复消息也包含此号码以匹配发件人。发送消息带有参数,将传递给远程方法,回复消息可能包含远程方法返回的错误或数据。Dbus中的方法调用流程如下:语言相关的绑定可能会提供一个代理(proxy)来调用进程对象中的方法,实际上是调用远程进程对象中的方法。在这种情况下,代理组织一个方法调用消息发送到远程进程。对于底层API,应用程序可以不使用代理,自行组织方法调用消息。方法调用消息将包含以下信息:远程进程的总线名称;方法名称;该方法所需的参数;远程进程的对象路径;包含方法的接口(interface)(可选)。方法调用消息发送给总线守护进程总线守护进程根据目的总线名称找到远程进程,并将消息发送给目标进程。如果未找到,则返回错误,并且接收方进程解压缩消息。在简单使用低级API的情况下,可以立即调用方法并将结果返回给总线守护进程。使用上层绑定时,绑定可能会检查对象路径、接口、方法,然后将方法调用消息转换为对本地对象(GObject、java.lang.Object、QObject等)的调用,然后将本地方法的返回值转换为方法的返回信息。Bus守护进程接收方法的返回消息,然后将其发送给方法调用的发送者。发送方收到回复消息,解析数据,可能会返回错误。使用绑定时,返回消息将被转换为代理方法(proxymethod)或异常的返回值。Bus守护进程不对消息进行排序,即如果两个方法调用消息发送给同一个接收者,则接收顺序与发送顺序相同。收件人不一定按照收到邮件的顺序回复邮件。例如,接收者可能在两个不同的线程中处理方法调用,先处理的消息先返回。发出信号信号由从一个进程发送到另一个进程或多个进程的消息组成。也就是说,该信号是一种单向广播。signal可能包含参数(data部分),既然是广播,就没有返回值。信号的发送者不知道接收者是谁。接收者需要在总线守护进程中注册,以便根据“匹配规则”接收信号,其中包含发送者和接收者的名称。总线守护进程只向对信号感兴趣的接收者发送信号。signal的流程大致如下:当使用dbus底层接口时,signal需要由应用程序自己创建并发送给daemon;使用dbus高层接口时,可以使用相关对象发送,比如Glib中提供的信号触发机制。信号的内容包括:信号的接口名称、信号名称、发送进程的总线名称以及其他参数。任何进程都可以根据“匹配规则”注册相关信号,守护进程有一个注册列表。守护进程检测信号,决定哪些进程对信号感兴趣,然后将信号发送给这些进程。每个进程收到信号后,如果使用dbus高层接口,可以选择在代理对象上触发信号。如果是dbus底层接口,需要检查sendername和signalname,然后再决定做什么。IntrospectionDbus对象支持org.freedesktop.DBus.Introspectable,dbus的标准接口,不带参数,返回描述接口、方法和信号的XML字符串。