总线上的每个连接都有一个或多个名字。当连接建立以后,D-Bus 服务会分配一个不可改变的连接名,称为唯一连接名(unique connection name),唯一连接名即使在进程结束后也不会再被其他进程所使用。唯一连接名以冒号开头,如“:34-907”。但唯一连接名总是临时分配,无法确定,也难以记忆,因此应用可以要求有另外一个名字公共名(well-known name)来对应唯一连接名。例如可以使用“com.mycompany”来映射“:34-907”。应用程序可能会要求拥有额外的公共名(well-known name)。例如,可以写一个规范来定义一个名字叫做 com.mycompany.TextEditor。协议可以指定自己拥有名字为com.mycompany.TextEditor的连接,一个路径为/com/mycompany/TextFileManager的对象,对象拥有接口org.freedesktop.FileHandler。应用程序就可以发送消息到总线上的连接名字,对象和接口以执行方法调用。连接名可以用于跟踪应用程序的生命周期。当应用退出(或者崩溃)时,与总线的连接将被OS内核关掉,总线将会发送通知,告诉剩余的应用程序。 D-Bus的对象和面向对象语言中的对象含义是不同的,D-Bus的对象表示的是D-Bus通道中信息流向的端点。对象由客户进程创建,并在连接进程中保持不变。所有使用D-BUS的应用程序都包含一些对象, 当经由一个D-BUS连接收到一条消息时,消息是被发往一个对象而不是整个应用程序。应用程序框架中定义了这样的对象,如GObject,QObject等,在D-Bus中称为原生对象(native object)。对于底层的D-Bus协议,即libdbus API,并不理会原生对象,使用对象路径(object path)的概念。通过对象路径,高层API接口可以绑定到对象,允许远程应用指向对象。对象路径如同文件系统路径,例如一个对象可能叫做“/org/kde/kspread/sheets/3/cells/4/5”。对象路径在全局(session或者system)是唯一的,用于消息的路由。 每一个对象支持一个或者多个接口,接口是一组方法和信号的集和,接口定义一个对象实体的类型。D-Bus对接口的命名方式,类似rospectable。开发人员通常使用编程语言名字作为接口名字。 每一个对象有两类成员:方法和信号。方法是一段函数代码,带有输入和输出;信号是广播给所有兴趣的其他实体,信号可以带有数据payload。客户向某对象发送一个请求,即对象被请求执行一个明确的、有名称的动作。如果客户请求执行一个目标对象未提供的方法,将会产生一个错误。方法的定义可以支持输入参数。对于每个请求,都有一个包含请求结果以及结果数据(输出参数)的响应返回给请求者。当请求无法完成时,响应中将包含异常信息,其中至少有异常名称以及错误信息。大多数语言都将这些封装在自身的语言机制中,比如将参数包装进消息包,将异常信息转换成语言自身的异常等等。在这些实现中,向远程对象传递一个字符串参数就好像是在本地执行一个字符串参数的函数一样简单。此时不再需要数据类型转换、数据复制等繁琐工作,语言本身封装了一切底层实现。 信号依然遵从面向对象概念,信号是从对象发出但没有特定目的******的单向数据广播。客户进程可以预先******其感兴趣的信号,如特定名称的信号或从某个对象发出的信号等。当对象发出信号后,所有订阅了该信号的客户进程将收到此信号的复本。接收端可能有多种情况出现,或者有一个客户进程,或者有多个客户进程,或者根本没有客户进程对这个信号感兴趣。对于信号来说没有响应消息,发出信号的对象不会知道是不是有客户进程在接收,有多少客户进程接收,以及从客户进程收到任何反馈。信号可以有参数。但信号是单向通信,因此不可能像方法一样具有输入输出参数。D-Bus允许客户进程通过参数比对过滤其需要的信号。信号一般用来广播一些客户可能会感兴趣的事件,比如某个其它的客户进程与总线的连接断开等。这些信号来自总线对象,因此从信号中客户进程可以分辨断线是由于正常退出、被杀掉或者程序崩溃。 |