总线名字(BUS NAME)
当每个应用程序向总线后台程序(BUS DAEMON)建立连接时,后台程序会立即为这个连接创建一个唯一的连接名(unique connection name).这个唯一的连接名一般都是以冒号:开始,类似:34-907.这个名字在应用程序的生命周期内都是被该应用程序唯一地占用。
应用程序也可以请求更直观的名字(well-known name),例如com.mycompany.TextEditor.应用程序然后就可以向这个总线名字上发送消息。
可以把唯一连接名看作是IP地址(192.168.0.5),而把直观名看作是域名(mycompany.com)。
总线名除了可以路由消息外,而可以用来跟踪连接的生命周期。当应用程序退出后,它的连接将会被操作系统内核关闭。总线后台程序将向其它应用程序发送通知消息,告诉它们这个应用程序的名字已经失去了它的所有者。另外,总线名还可以用来协调单例应用程序,应用程序启动时如果发现它所请求的名字已经占用,就会退出,只允许该应用程序的一个实例存在。
地址(Address)
一个D-Bus服务器程序会在某个地址上侦听,其它的客户端程序连向这个地址。例如unix:path=/tmp/abcdef指定了服务器将在一个UNIX domain socket的路径/tmp/abcdef上侦听消息,客户端将向这个socket上发起连接。
当我们利用消息总线后台程序(message bus daemon)来创建D-Bus应用程序时,libdbus会通过读取系统变量,自动地找出per-session bus daemon的地址。通过检查一个命名好的Unix domain socket路径来发现系统BUS daemon的地址。
当我们不使用消息总线后台程序来创建D-Bus应用程序时,程序员将负责定义哪个是服务器,哪个是客户端,并且提供一种机制来使它们遵守同样的服务器地址。这种情况一般很少见。
概念图(Conceptual Picture)
Address -> [Bus Name] -> Path -> Interface -> Method
方括号内的总线名是可选的,也就是说只有在使用消息后台程序(message bus daemon)时,它才用来将方法调用路由到合适的应用程序。如果是应用程序间的直接连接(不通过daemon),总线名就没有必要了。
其它接口名也是可选的,如果同一个对象路径上没有重名的方法名字的话。
方法调用(Method Call)
总线后台程序不会为消息排序。接收端将会以消息的发送顺序来接收消息,但是接收端并不会保证消息返回时也是按原来顺序返回,例如接收方可能将方法调用处理放在不能的线程里执行,消息返回的顺序依赖了各线程的完成时间。消息调用者使用方法调用(method calls)的一个唯一的序列号来匹配返回消息。
内省(Introspection)
D-Bus对象可以支持一个特定的接口:org.freedesktop.DBus.Introspectable.这个接口有一个方法org.freedesktop.Introspect,这个方法没有参数,返回一个XML字符串。这个XML字符串描述这个对象的接口、方法和信号。
Glib binding示例
int
main (int argc, char **argv)
{
DBusGConnection *connection;
GError *error;
DBusGProxy *proxy;
char **name_list;
char **name_list_ptr;
g_type_init ();
error = NULL;
connection = dbus_g_bus_get (DBUS_BUS_SESSION,
&error);
if (connection == NULL)
{
g_printerr ("Failed to open connection to bus: %s\n",
error->message);
g_error_free (error);
exit (1);
}
/* Create a proxy object for the "bus driver" (name "org.freedesktop.DBus") */
proxy = dbus_g_proxy_new_for_name (connection,
DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS);
/* Call ListNames method, wait for reply */
error = NULL;
if (!dbus_g_proxy_call (proxy, "ListNames", &error, G_TYPE_INVALID,
G_TYPE_STRV, &name_list, G_TYPE_INVALID))
{
/* Just do demonstrate remote exceptions versus regular GError */
if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION)
g_printerr ("Caught remote method exception %s: %s",
dbus_g_error_get_name (error),
error->message);
else
g_printerr ("Error: %s\n", error->message);
g_error_free (error);
exit (1);
}
/* Print the results */
g_print ("Names on the message bus:\n");
for (name_list_ptr = name_list; *name_list_ptr; name_list_ptr++)
{
g_print (" %s\n", *name_list_ptr);
}
g_strfreev (name_list);
g_object_unref (proxy);
return 0;
}