Chinaunix首页 | 论坛 | 博客
  • 博客访问: 185931
  • 博文数量: 49
  • 博客积分: 2065
  • 博客等级: 大尉
  • 技术积分: 413
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-08 17:04
文章分类

全部博文(49)

文章存档

2012年(2)

2010年(17)

2009年(30)

我的朋友

分类: 嵌入式

2009-09-11 11:25:58

D-BUS的内部工作:
    一个典型的D-BUS设置由几个bus组成:
         a persistent system bus:它将在系统启动时被执行,这个bus将被系统和后台程序使用。这个bus有非常高的安全性,以致于任何的应用程序都不能欺骗过系统事件。
         many session buses:它们在用户登录时启动并且规此用户私有。用户的应用程序将通过这种session bus通信。当然,如果一个应用程序想从system bus接收消息,那它可以先跟system bus很好的连接,但是应用程序发送消息将被限制。

    一旦应用程序连接到一个bus, 它们必须声明要接收所增加的配对程序的哪些消息。配对应用程序为消息指定一套规则,这套规则将基于接口、对象路径和方法。这将使应用程序能够集中于处理它想处理的东西,能够考虑到高效的消息路由,能够使多数消息在通过buses时从所有应用程序的性能上保持优先(感觉这句很难翻译,英文原文: to keep the anticipated multitude of messages across buses from grinding the performance of all of the applications down to a crawl.)

对象

    重点来说D-BUS是一个peer-to-peer协议---每个消息有一个来源和终点, 这些地址被作为对象路径来指定。从概念上说,所有使用D-BUS的应用程序包括一个对象的设置, 并且消息从指定的对象被发送,而不是应用程序,这个指定的被对象被对象路径鉴定确认

    另外,每个对象可以支持一个或多个接口。这些接口类似于interfaces in Java or pure virtual classes in C++.尽管如此,没有一个操作检查是否对象实现了它们要求的接口,并且没有办法从内部查看一个对象所列出的它所支持的接口。接口被用于名称空间的方法名, 所以一个单独的对象可以用同一个名称拥有多重的方法但是是不同的接口。

消息

    在D-BUS中有4种类型的消息:方法调用、方法返回、信号、错误。为了在一个D-BUS对象中执行一个方法, 你发送一个方法调用消息给对象. 它将做一些数据处理并且返回一个方法或者消息或者错误信息。信号是不同的,在信号中它们不能返回任何东西:既不是一个"signal return" 消息也不是任何其他类型的错误消息。

    消息也可以有任何的参数。参数有明显的类型(booleans, bytes, integers,strings, arrays, and dictionaries)

服务

    服务在D-BUS中是最高级别的抽象, 一个应用程序可以用一个bus注册一个服务,如果注册成功,应用程序就已经获得了这个服务。其他应用程序可以检查在bus里是否存在一个特定的服务,也可以让bus启动服务如果服务未启动。

Even though D-BUS is relatively new, it has been adopted very quickly. As I mentioned earlier, udev can be built with D-BUS support so that it sends a signal when a device is hot-plugged. Any application can listen to these events and perform actions when they are received. For example, gnome-volume-manager can detect the insertion of a USB memory stick and automatically mount it; or, it can automatically download photos when a digital camera is plugged in.

A more amusing but far less useful example is the combination of Jamboree and Ringaling. Jamboree is a simple music player that has a D-BUS interface so that it can be told to play, go to the next song, change the volume, and so on. Ringaling is a small program that opens /dev/ttyS0 (a serial port) and watches what is received. When Ringaling sees the text "RING," it uses D-BUS to tell Jamboree to turn down the volume. The net result is that if you have a modem plugged into your computer and your phone rings, the music is turned down for you. This is what computers are for!

Now, let's walk through a few example uses of D-BUS code.

dbus-ping-send.c sends a signal over the session bus every second with the string "Ping!" as an argument. I'm using GLib to manage the bus so that I don't need to deal with the details of the bus connection myself.



#include
#include
#include

static gboolean send_ping (DBusConnection *bus);

int main (int argc, char **argv)
{
  GMainLoop *loop;
  DBusConnection *bus;
  DBusError error;

  /*  1. Create a new event loop to run in */
  loop = g_main_loop_new (NULL, FALSE);

  /*  2. Get a connection to the session bus */
  dbus_error_init (&error);
  bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
  if (!bus) {
    g_warning ("Failed to connect to the D-BUS daemon: %s", error.message);
    dbus_error_free (&error);
    return 1;
  }

  /*  3. Set up this connection to work in a GLib event loop */
  dbus_connection_setup_with_g_main (bus, NULL);

  /* 4. Every second call send_ping() with the bus as an argument*/
  g_timeout_add (1000, (GSourceFunc)send_ping, bus);

  /* 5. Start the event loop */
  g_main_loop_run (loop);
  return 0;
}

static gboolean
send_ping (DBusConnection *bus)
{
    printf("this is sub function\n");
    const char *v_STRING = "Ping!!!";

    DBusMessage *message;

    /* Create a new signal "Ping" on the "com.burtonini.dbus.Signal" interface,
    * from the object "/com/burtonini/dbus/ping". */
    message = dbus_message_new_signal("/com/burtonini/dbus/ping", "com.burtonini.dbus.Signal", "Ping");

    dbus_message_set_no_reply(message, TRUE);
    
    /* Append the string "Ping!" to the signal */
    dbus_message_append_args(message, DBUS_TYPE_STRING, &v_STRING, DBUS_TYPE_INVALID);
 
    /* Send the signal */
    dbus_connection_send(bus, message, NULL);

    /* Free the signal now we have finished with it */  
    dbus_message_unref(message);

    /* Tell the user we send a signal */
    g_print("Ping!\n");

    /* Return TRUE to tell the event loop we want to be called again */
    return TRUE;
}

Makefile:
BIN = dbus-send

SRCS=$(wildcard *.c)
OBJS=$(patsubst %.c,%.o,$(SRCS))

#all:$(BIN)

%.o:%.c
    gcc  -g $< -o $@ -c `pkg-config  dbus-glib-1 --cflags`
   
$(BIN):$(OBJS)
    gcc  $(OBJS) -o $(BIN) `pkg-config  dbus-glib-1 --libs`

clean:
    rm -rf *.o $(BIN)

explain:
    @echo Source files----------
    @echo $(SRCS)
    @echo Object files----------
    @echo $(OBJS)
    @echo Binary files----------
    @echo $(BIN)

The main function creates a GLib event loop, gets a connection to the session bus, and integrates the D-BUS event handling into the Glib event loop. Then it creates a one-second timer that calls send_ping, and starts the event loop.

send_ping constructs a new Ping signal, coming from the object path /com/burtonini/dbus/ping and interface com.burtonini.dbus.Signal. Then the string "Ping!" is added as an argument to the signal and sent across the bus. A message is printed on standard output to let the user know a signal was sent.

Of course, it is not good to fire signals down the bus if there is nothing listening to them... which brings us to:



#include
#include
#include

static DBusHandlerResult signal_filter
      (DBusConnection *connection, DBusMessage *message, void *user_data);

int main (int argc, char **argv)
{
  GMainLoop *loop;
  DBusConnection *bus;
  DBusError error;
 
  /*  1. Create a new event loop to run in */
  loop = g_main_loop_new (NULL, FALSE);

  /*  2. Get a connection to the session bus */
  dbus_error_init (&error);
  bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
  if (!bus) {
    g_warning ("Failed to connect to the D-BUS daemon: %s", error.message);
    dbus_error_free (&error);
    return 1;
  }

  /*  3. Set up this connection to work in a GLib event loop */
  dbus_connection_setup_with_g_main (bus, NULL);

  /* 4. listening to messages from all objects as no path is specified */
  dbus_bus_add_match (bus, "type='signal',interface='com.burtonini.dbus.Signal'", NULL);
  dbus_connection_add_filter (bus, signal_filter, loop, NULL);

  /* 5. Start the event loop */
  g_main_loop_run (loop);
  return 0;
}

static DBusHandlerResult
signal_filter (DBusConnection *connection, DBusMessage *message, void *user_data)
{
  /* User data is the event loop we are running in */
  GMainLoop *loop = user_data;

  /* A signal from the bus saying we are about to be disconnected */
  if ( dbus_message_is_signal(message, "org.freedesktop.Local", "Disconnected") )
 {
    /* Tell the main loop to quit */
    g_main_loop_quit (loop);
    /* We have handled this message, don't pass it on */
    return DBUS_HANDLER_RESULT_HANDLED;
  }
  /* A Ping signal on the com.burtonini.dbus.Signal interface */
  else if (dbus_message_is_signal (message, "com.burtonini.dbus.Signal", "Ping"))
 {
    DBusError error;
    char *s;
    dbus_error_init (&error);
    if (dbus_message_get_args
       (message, &error, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID))
    {
      g_print("Ping received: %s\n", s);
      // dbus_free (s);
    }
    else
    {
      g_print("Ping received, but error getting message: %s\n", error.message);
      dbus_error_free (&error);
    }
    return DBUS_HANDLER_RESULT_HANDLED;
  }
  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}

Makefile:
BIN = dbus-listen

SRCS=$(wildcard *.c)
OBJS=$(patsubst %.c,%.o,$(SRCS))

#all:$(BIN)

%.o:%.c
    gcc  -g $< -o $@ -c `pkg-config  dbus-glib-1 --cflags`
   
$(BIN):$(OBJS)
    gcc  $(OBJS) -o $(BIN) `pkg-config  dbus-glib-1 --libs`

clean:
    rm -rf *.o $(BIN)

explain:
    @echo Source files----------
    @echo $(SRCS)
    @echo Object files----------
    @echo $(OBJS)
    @echo Binary files----------
    @echo $(BIN)

This program listens for the signals dbus-ping-send.c is emitting. The main function starts as before, creating a connection to the bus. Then it states that it would like to be notified when signals with the com.burtonini.dbus.Signal interface are sent, sets signal_filter as the notification function, and enters the event loop.

signal_func is called when a message that meets the matches is sent. However, it will also receive bus management signals from the bus itself. Deciding what to do when a message is received is a simple case of examining the message header. If the message is a bus disconnect signal, the event loop is terminated, as there is no point in listening to a non-existent bus. (The bus is told that the signal was handled). Next, the incoming message is compared to the message we are expecting, and, if successful, the argument is extracted and output. If the incoming message is neither of those, the bus is told that we did not handle the message.

Those two examples used the low-level D-BUS library, which is complete but can be long-winded to use when you want to create services and many objects. This is where the higher-level bindings come in. There are C# and Python wrappers in development that present a programming interface far closer to the logical model of D-BUS. As an example, here is a more sophisticated reworking of the ping/listen example in Python. Because the Python bindings model the logical interface, it is not possible to send a signal without it coming from a service. So this example also creates a service:



#! /usr/bin/env python

import gtk
import dbus

# Connect to the bus
bus = dbus.Bus()

# Create a service on the bus
service = dbus.Service("com.burtonini.dbus.SignalService", bus)

# Define a D-BUS object
class SignalObject(dbus.Object):
def __init__(self, service):
dbus.Object.__init__(self, "/", [], service)

# Create an instance of the object, which is part of the service
signal_object = SignalObject(service)

def send_ping():
signal_object.broadcast_signal("com.burtonini.dbus.Signal", "Ping")
print "Ping!"
return gtk.TRUE

# Call send_ping every second to send the signal
gtk.timeout_add(1000, send_ping)
gtk.main()

Most of the code is self-explanatory: a connection to the bus is obtained, and the service com.burtonini.dbus.SignalService is registered. Then a minimal D-BUS object is created and every second a signal is broadcast from the object. This code is clearer than the corresponding C code, but the Python bindings still need work. (For instance, there is no way to add arguments to signals.)



#! /usr/bin/env python

import gtk
import dbus

bus = dbus.Bus()

def signal_callback(interface, signal_name, service, path, message):
print "Received signal %s from %s" % (signal_name, interface)

# Catch signals from a specific interface and object, and call signal_callback
# when they arrive.
bus.add_signal_receiver(signal_callback,
"com.burtonini.dbus.Signal", # Interface
None, # Any service
"/" # Path of sending object
)

# Enter the event loop, waiting for signals
gtk.main()

This code is more concise than the equivalent C code in dbus-ping-listen.c and is easier to read. Again, there are areas where the bindings still need work (when calling bus.add_signal_receiver, the user must pass in an interface and an object path; otherwise, malformed matchers are created). This is a trivial bug, and once it is fixed, the service and object path arguments could be removed, improving the readability of the code even more.


D-BUS is a lightweight yet powerful remote procedure call system with minimal overhead costs for the applications that wish to use it. D-BUS is under active public development by a group of very experienced programmers. Acceptance of D-BUS by early adopters is rapid, so it appears to have a rosy future on the Linux desktop.


发现一篇翻译总结dbus的文章比我的好多了
http://www.ibm.com/developerworks/cn/linux/l-dbus.html
dbus编程基础:
http://socol.javaeye.com/blog/518918
阅读(2611) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~