D-Bus是一个用于进程间通讯的系统。从架构上来讲,分为三部分:java
libdbus只支持one-to-one类型的链接,如同原始套接字那样,区别是,发送的不是字节流(byte streams)而是消息。消息包含消息header和body,header标明信息类型,body包含消息主体内容。 Libdbus也能够容许实现特定的传输通道,从而来完成好比像认证之类的应用细节。python
消息总线守护进程将D-bus上链接的全部程序构成一个轮形hub。轮子上的每个轮辐都是基于libdbus的一对一链接,链接了一个app。app经过轮辐向daemon发送消息,daemon在合适的时机将消息转发到其余已链接的app。daemon能够理解为一个路由器。编程
总线守护进程在系统中有多个实例。好比全局惟一的实例,一个如同sendmail或者Apache的系统daemon,对于接收什么样消息用来进程间通讯,有着很严格的安全要求(system bus?)。另一些daemon实例由用户登陆时创建,用于该用户的session中的app之间通讯。api
系统级的daemon和per-user daemon是分离的。session内的IPC不会影响系统级的message bus,反之亦然。安全
有许多技术用来实现IPC或者网络信息传递,好比:CORBA, DCE, DCOM, DCOP, XML-RPC, SOAP, MBUS, Internet Communications Engine (ICE)。每一种都是针对特定种类的应用程序量身定作的。
Dbus为两种状况而生:网络
开发者在本身的编程架构中会定义object,一般基于一个基础的类,好比 java.lang.Object, GObject, QObject, python's base Object, or whatever. 咱们称为native object。session
dbus协议和libdbus中的api不关心native object如何定义,而是提供了object path的概念。有了object path,上层的bindings就可以命名native object实例,而且容许远程的app引用这些object。
object path如同文件系统中的文件路径。好比,一个object能够被命名为/org/kde/kspread/sheets/3/cells/4/5。易于理解的路径很棒,若有须要的话,是你也能够命名为诸如 /com/mycompany/c5yo817y0c1y1c5b。
名称中指定命名空间是明智的作法,好比将路径开头设置为你开发的domain名称。这样能够保证同一进程中的不一样模块互不干扰。架构
每一个object都有成员(members),成员分为方法(methods)和信号(signals)。方法(methods)是object能够调用的一组操做,带有输入或者输出参数。信号被广播到任何一个对该信号感兴趣的对象;信号也能够承载数据。app
引用方法或者信号都是经过它们的名字,好比Frobate或者OnClickeddom
一个object只是一个或多个interface。一个interface中包含了一组方法和信号(methods and signals),概念如同 GLib or Qt or Java中的方法和信号。接口定义了object实例的类型。
dbus用简单的命名空间字符串标识一个interface,好比org.freedesktop.Introspectable;大多数绑定会将这些interface直接映射到对应的编程语言结构,好比Java接口或者C++的纯虚类。
代理(proxy)object是native object,用于表明其余进程中的远程object。底层的DBus API建立一个Methods call,发送,而后接收,处理这些回复的消息。能够把代理看作是一个普通的native object,可是当你调用代理中的方法,绑定(bindings)将该操做转化为
dbus Method call消息,等待远端回复消息,将返回值解包,而后返回到native 方法......
如下是一个伪代码的例子,不使用proxy:
Message message = new Message("/remote/object/path", "MethodName", arg1, arg2); Connection connection = getBusConnection(); connection.send(message); Message reply = connection.waitForReply(message); if (reply.isError()) { } else { Object returnValue = reply.getReturnValue(); }
使用proxy
Proxy proxy = new Proxy(getBusConnection(), "/remote/object/path"); Object returnValue = proxy.MethodName(arg1, arg2);
每当app链接dbus daemon时,daemon为app分配一个惟一的链接名字,以冒号开头。一个bus name永远指向同一个app,不会被复用。例如:34-907。冒号后面的数字除了它们的惟一性没有意义。
app也能够请求便于理解的名字。好比,com.mycompany.TextEditor。对应的object的路径能够为/com/mycompany/TextFileManager,interface为org.freedesktop.FileHandler
能够将:34-907(unique name)看成是IP地址,com.mycompany.TextEditor看成是域名。com.mycompany.TextEditor映射 :34-907就如沟通mycompany.com映射到192.168.0.5。
除了路由消息,bus name还可用来追踪app生命周期。当一个app退出或者crash时,操做系统内核(operating system kernel)会断开message bus的链接,而后message bus发送消息通知
其余app该name已经失去owner了。经过追踪这些notification,能够检测其余app的生命周期。
Bus name名字还能够检测应用是否已经启动,这能够用来实现单实例启动程序。
应用做为dbus的server或者client,server监听来自client的链接,client链接到server。一旦链接创建,它就是一个对称的消息流。
Dbus address指明server去哪监听,client去哪里链接。例如,地址unix:path=/tmp/abcdef指明了server将监听一个Unix socket,路径是/tmp/abcdef, client将链接到这个socket。
address也能指定TCP/IP sockets,或者其余类型的传输方式。
Big Conceptual Picture
把上面的概念组合起来获得如下流程:
Address -> [Bus Name] -> Path -> Interface -> Method
Dbus工做原理是在两个进程之间发送消息,若是工做在至关上层的binging中,是不会直接处理消息的。
四种类型消息:
每一个消息有一个消息头,包含field和body和桉树。能够将header看成消息的路由信息,body看成消息体。header可能包含如下信息:发送方bus name,目的地的busname,调用的方法或者信号,等等。
header中有一个描述body中值的类型的field。好比,字母i岱庙32位整数,ii标识body有两个32位整数。
一个方法调用(method call)由两条消息组成,一个方法调用消息从进程A发送给进程B,对应的方法返回消息从进程B发送给进程A,发送和返回消息都要通过bus daemon路由。
每一个call消息包含一串独有的数字,reply消息也包含这个数字以便和发送方匹配。
发送消息带有参数,会传递给远程method,回复消息可能包含一个错误或者远程method返回的数据。
Dbus中的方法调用流程以下:
Bus daemon不会为消息排序,也就是说,若是发送两条method call消息到同一接收方,接收的顺序与发送顺序相同。接收方不必定按照接收的顺序来回复消息。好比,接收方可能在两个不一样的线程中处理method call,哪一个消息先处理完就先返回。
信号由一条消息组成,从一个进程发送到另外一个或多个进程。也就是说,信号是单向的广播。信号可能包含参数(数据部分),由于它是一个广播,没有返回值。
信号的发送者不知道接受者是谁。接收者为了接收信号须要向bus daemon进行注册,基于“match rules”,这些规则包含了发送者和接受者的名字。Bus daemon只将信号发送给对该信号感兴趣的接收者。
信号的流程大体以下:
Dbus objects支持org.freedesktop.DBus.Introspectable,dbus的标准接口,无需参数,返回一个XML字符串,描述了接口,方法,信号。