Maemo Linux手机平台系列分析:9 Maemo平台开发之 使用D-Bus信号做异步操作

A1: 嵌入式Linux开发 专栏收录该内容
56 篇文章 0 订阅
  
 
使用D-Bus信号做异步操作
  • D-Bus信号的属性
  • XML文件中声明信号
  • GObject对象中发射信号
  • 在客户端捕获信号
  • 跟踪D-Bus信号
D-Bus信号的属性:
      通过D-Bus实现远程函数调用(RPC)只是D-Bus的一半功能,另外D-Bus也支持广播通信,也称之为异步通信。这种异步通信机制在D-Bus中被称为信号。当你需要把一个状态的变化给通知很多程序时,这种机制是非常有用的。比如说:系统马上要关机;网络已经断开,这些情况下,接收程序不必要持续轮询这种状态,而由系统发广播通知就行了。
     不过,信号也不能解决所有问题:如果接收程序并没有能力去快速地处理发给它的D-Bus消息,这个信号可能会丢失!可能还有其它的某些问题,这些问题也是其它RPC机制所共同面临的问题,并非D-Bus的特性。正因为此,如果你的程序需要格外的稳定,你需要想办法去解决这个问题。一种方法是:时不时地检查你关系的状态,不过不能太频繁了,也不能次数太少,需要仔细权衡。
      D-Bus的信号可以携带一些信息。每个信号有它自己的名字(在XML中指定)和参数。信号的参数列表实际上仅仅说明在信号中传递的信息列表,不要和method的参数混淆。
信号无“返回值”,就是说当D-Bus信号发送出去后,是接收不到返回的或者就不希望接收返回值。因此,如果你需要确认信号是否发送成功,你要自己想办法了。D-Bus信号和网络上的数据报(datagram)很类似,比如UDP
     D-Bus的很多语言绑定都试图把D-Bus的信号机制映射到目标语言中,由于Glib已经对signal有很好的支持,因此这种映射就变得水到渠成了。因此下面的例子中,你的客户端的代码将注册Glib信号,并且在回调函数中处理信号(有个特定的函数用来注册信号:dbus_g_proxy_connect_signal)。
 
XML接口文件中声明信号:
下面我们将对前一个例子做些扩展:增加两个阈值 (最小值和最大值),并且当设置操作越界时,对象将发射信号。另外,当对象的值发生改变时,对象也发射信号。
定义4个信号:
<node>
 <interface name="org.maemo.Value">
 
 <!-- ... Listing cut for brevity ... -->
 
    <!-- Signal (D-Bus) definitions -->
 
    <!-- NOTE: The current version of dbus-bindings-tool doesn't
         actually enforce the signal arguments _at_all_. Signals need
         to be declared in order to be passed through the bus itself,
         but otherwise no checks are done! For example, you could
         leave the signal arguments unspecified completely, and the
         code would still work. -->
 
    <!-- Signals to tell interested clients about state change.
         We send a string parameter with them. They never can have
         arguments with direction=in.
// 对象的信号,主要是告诉对该信号感兴趣的客户端:对象的状态发生了改变了,我们发送一个字符串通知出去,因此这里必须是出口参数 -->
    <signal name="changed_value1">
      <arg type="s" name="change_source_name" direction="out"/>
    </signal>
 
    <signal name="changed_value2">
      <arg type="s" name="change_source_name" direction="out"/>
    </signal>
 
    <!-- Signals to tell interested clients that values are outside
         the internally configured range (thresholds). -->
    <signal name="outofrange_value1">
      <arg type="s" name="outofrange_source_name" direction="out"/>
    </signal>
    <signal name="outofrange_value2">
      <arg type="s" name="outofrange_source_name" direction="out"/>
    </signal>
 
 </interface>
</node>
    如果你使用 dbus-binding-tool 工具来生成代码的话,信号的定义是要的,但是这个工具目前对于信号的参数列表支持的还不够好,实际上,这个工具会忽略你定义的参数,因此你要手动去写实现信号动作的很多代码。将来,这个工具可能会支持信号参数列表,不过目前我们只有自己干了!
对象发射信号:
    因此,我们可以很容易修改信号的名字,我们把它们定义在一个头文件中,并且在 client 侧和 server 侧使用同一个头文件:
/* Symbolic constants for the signal names to use with GLib.
   These need to map into the D-Bus signal names. */
#define SIGNAL_CHANGED_VALUE1    "changed_value1"
#define SIGNAL_CHANGED_VALUE2    "changed_value2"
#define SIGNAL_OUTOFRANGE_VALUE1 "outofrange_value1"
#define SIGNAL_OUTOFRANGE_VALUE2 "outofrange_value2"
GObject 可以发射 Glib 信号之前,这个信号需要被定义和创建。你最好在类构造函数中做这件事,因为信号类型只需要创建一次:
/**
 * Define enumerations for the different signals that we can generate
 * (so that we can refer to them within the signals-array [below]
 * using symbolic names). These are not the same as the signal name
 * strings.
 *
 * NOTE: E_SIGNAL_COUNT is NOT a signal enum. We use it as a
 *       convenient constant giving the number of signals defined so
 *       far. It needs to be listed last.
 */
typedef enum {
 E_SIGNAL_CHANGED_VALUE1,
 E_SIGNAL_CHANGED_VALUE2,
 E_SIGNAL_OUTOFRANGE_VALUE1,
 E_SIGNAL_OUTOFRANGE_VALUE2,
 E_SIGNAL_COUNT
} ValueSignalNumber;
 
 /*... Listing cut for brevity ...*/
 
typedef struct {
 /* The parent class state. */
 GObjectClass parent;
 /* The minimum number under which values will cause signals to be
     emitted. */
 gint thresholdMin;
 /* The maximum number over which values will cause signals to be
     emitted. */
 gint thresholdMax;
 /* Signals created for this class. */
 guint signals[E_SIGNAL_COUNT];
} ValueObjectClass;
 
 /*... Listing cut for brevity ...*/
 
/**
 * Per class initializer
 *
 * Sets up the thresholds (-100 .. 100), creates the signals that we
 * can emit from any object of this class and finally registers the
 * type into the GLib/D-Bus wrapper so that it may add its own magic.
 */
static void value_object_class_init(ValueObjectClass* klass) {
 
 /* Since all signals have the same prototype (each will get one
     string as a parameter), we create them in a loop below. The only
     difference between them is the index into the klass->signals
     array, and the signal name.
 
     Since the index goes from 0 to E_SIGNAL_COUNT-1, we just specify
     the signal names into an array and iterate over it.
 
     Note that the order here must correspond to the order of the
     enumerations before. */
 const gchar* signalNames[E_SIGNAL_COUNT] = {
    SIGNAL_CHANGED_VALUE1,
    SIGNAL_CHANGED_VALUE2,
    SIGNAL_OUTOFRANGE_VALUE1,
    SIGNAL_OUTOFRANGE_VALUE2 };
 /* Loop variable */
 int i;
 
  dbg("Called");
 g_assert(klass != NULL);
 
 /* Setup sane minimums and maximums for the thresholds. There is no
     way to change these afterwards (currently), so you can consider
     them as constants. */
 klass->thresholdMin = -100;
 klass->thresholdMax = 100;
 
 dbg("Creating signals");
 
 /* Create the signals in one loop, since they all are similar
     (except for the names). */
 for (i = 0; i < E_SIGNAL_COUNT; i++) {
    guint signalId;
 
    /* Most of the time you will encounter the following code without
       comments. This is why all the parameters are documented
       directly below. */
    signalId =
      g_signal_new(signalNames[i], /* str name of the signal */
                   /* GType to which signal is bound to */
                   G_OBJECT_CLASS_TYPE(klass),
                   /* Combination of GSignalFlags which tell the
                      signal dispatch machinery how and when to
                      dispatch this signal. The most common is the
                      G_SIGNAL_RUN_LAST specification. */
                   G_SIGNAL_RUN_LAST,
                   /* Offset into the class structure for the type
                      function pointer. Since we're implementing a
                      simple class/type, we'll leave this at zero. */
                   0,
                   /* GSignalAccumulator to use. We don't need one. */
                   NULL,
                   /* User-data to pass to the accumulator. */
                   NULL,
                   /* Function to use to marshal the signal data into
                      the parameters of the signal call. Luckily for
                      us, GLib (GCClosure) already defines just the
                      function that we want for a signal handler that
                      we don't expect any return values (void) and
                      one that will accept one string as parameter
                      (besides the instance pointer and pointer to
                      user-data).
 
                      If no such function would exist, you would need
                      to create a new one (by using glib-genmarshal
                      tool). */
                   g_cclosure_marshal_VOID__STRING,
                   /* Return GType of the return value. The handler
                      does not return anything, so we use G_TYPE_NONE
                      to mark that. */
                   G_TYPE_NONE,
                   /* Number of parameter GTypes to follow. */
                   1,
                   /* GType(s) of the parameters. We only have one. */
                   G_TYPE_STRING);
    /* Store the signal Id into the class state, so that we can use
       it later. */
    klass->signals[i] = signalId;
 
    /* Proceed with the next signal creation. */
 }
 /* All signals created. */
 
 dbg("Binding to GLib/D-Bus");
 
 /*... Listing cut for brevity ...*/
 
}
 
信号类型是保存在类结构中的,因此很容易引用。类构造函数设置阈值的上下限。
发射信号是比较容易的,为了减少重复代码,我们写一个工具函数,专门来发射信号:
/**
 * Utility helper to emit a signal given with internal enumeration and
 * the passed string as the signal data.
 *
 * Used in the setter functions below.
 */
static void value_object_emitSignal(ValueObject* obj,
                                    ValueSignalNumber num,
                                    const gchar* message) {
 
 /* In order to access the signal identifiers, we need to get a hold
     of the class structure first.
// 由于信号是定义在类结构中的,而不是对象结构中的,为了能访问信号,我们首先需要取得类结构 */
 ValueObjectClass* klass = VALUE_OBJECT_GET_CLASS(obj);
 
 /* Check that the given num is valid (abort if not).
     Given that this file is the module actually using this utility,
     you can consider this check superfluous (but useful for
     development work). */
 g_assert((num < E_SIGNAL_COUNT) && (num >= 0));
 
 dbg("Emitting signal id %d, with message '%s'", num, message);
 
 /* This is the simplest way of emitting signals. */
 g_signal_emit(/* Instance of the object that is generating this
                   signal. This will be passed as the first parameter
                   to the signal handler (eventually). But obviously
                   when speaking about D-Bus, a signal caught on the
                   other side of D-Bus will be first processed by
                   the GLib-wrappers (the object proxy) and only then
                   processed by the signal handler. */
                obj ,//这个是对象实例
                /* Signal id for the signal to generate. These are
                   stored inside the class state structure. */
                klass->signals[num],
                /* Detail of signal. Since we are not using detailed
                   signals, we leave this at zero (default). */
                0,
                /* Data to marshal into the signal. In our case it's
                   just one string. */
                message);
 /* g_signal_emit returns void, so we cannot check for success. */
 
 /* Done emitting signal. */
}
再写个检查阈值的工具函数:
/**
 * Utility to check the given integer against the thresholds.
 * Will return TRUE if thresholds are not exceeded, FALSE otherwise.
 *
 * Used in the setter functions below.
 */
static gboolean value_object_thresholdsOk(ValueObject* obj,
                                          gint value) {
 
 /* Thresholds are in class state data, get access to it */
 ValueObjectClass* klass = VALUE_OBJECT_GET_CLASS(obj);
 
 return ((value >= klass->thresholdMin) &&
          (value <= klass->thresholdMax));
}
 
下面利用上面的两个工具函数修改值,并发射信号:
/**
 * Function that gets called when someone tries to execute "setvalue1"
 * over the D-Bus. (Actually the marshalling code from the stubs gets
 * executed first, but they will eventually execute this function.)
 */
/* 这个函数是在server侧实现的,1:当client侧的异步调用发出后,会把消息发送给D-Bus,2:D-Bus进而会调用这个server侧的函数;3:这个函数发射信号,发射给client侧的接收者 */
gboolean value_object_setvalue1(ValueObject* obj, gint valueIn,
                                                  GError** error) {
 
 dbg("Called (valueIn=%d)", valueIn);
 
 g_assert(obj != NULL);
 
 /* Compare the current value against old one. If they're the same,
     we don't need to do anything (except return success). */
 if (obj->value1 != valueIn) {
    /* Change the value. */
    obj->value1 = valueIn;
 
    /* Emit the "changed_value1" signal. */
    value_object_emitSignal(obj, E_SIGNAL_CHANGED_VALUE1, "value1");
 
    /* If new value falls outside the thresholds, emit
       "outofrange_value1" signal as well. */
    if (!value_object_thresholdsOk(obj, valueIn)) {
      value_object_emitSignal(obj, E_SIGNAL_OUTOFRANGE_VALUE1,
                                   "value1");
    }
 }
 /* Return success to GLib/D-Bus wrappers. In this case we don't need
     to touch the supplied error pointer-pointer. */
 return TRUE;
}
下面我们编译 server 侧的代码,并且在后台运行:
[sbox-CHINOOK_X86: ~/glib-dbus-signals] > make server
dbus-binding-tool --prefix=value_object --mode=glib-server /
 value-dbus-interface.xml > value-server-stub.h
cc -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include /
 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -g -Wall /
 -DG_DISABLE_DEPRECATED -DNO_DAEMON -DPROGNAME=/"server/" /
  -c server.c -o server.o
cc server.o -o server -ldbus-glib-1 -ldbus-1 -lgobject-2.0 -lglib-2.0
[sbox-CHINOOK_X86: ~/glib-dbus-signals] > run-standalone.sh ./server &
[1] 15293
server:main Connecting to the Session D-Bus.
server:main Registering the well-known name (org.maemo.Platdev_ex)
server:main RequestName returned 1.
server:main Creating one Value object.
server:value_object_class_init: Called
server:value_object_class_init: Creating signals
server:value_object_class_init: Binding to GLib/D-Bus
server:value_object_class_init: Done
server:value_object_init: Called
server:main Registering it on the D-Bus.
server:main Ready to serve requests (daemonizing).
server: Not daemonizing (built with NO_DAEMON-build define)
[sbox-CHINOOK_X86: ~/glib-dbus-signals] >
 
下面,我们运行 client 侧的程序,看看效果 :
[sbox-CHINOOK_X86: ~/glib-dbus-signals] > run-standalone.sh dbus-send /
 --type=method_call --print-reply --dest=org.maemo.Platdev_ex /
 /GlobalValue org.maemo.Value.setvalue1 int32:10 // 传入的10是处于阈值范围内的,所以server侧只会发发射一个消息:值被修改的消息
server:value_object_setvalue1: Called (valueIn=10)
server:value_object_emitSignal: Emitting signal id 0, with message 'value1'
method return sender=:1.38 -> dest=:1.41
[sbox-CHINOOK_X86: ~/glib-dbus-signals] > run-standalone.sh dbus-send /
 --type=method_call --print-reply --dest=org.maemo.Platdev_ex /
 /GlobalValue org.maemo.Value.setvalue1 int32:-200 // 传入的-200正好在阈值上,所以server侧会发送两个消息:值被修改;并且越界了;
server:value_object_setvalue1: Called (valueIn=-200)
server:value_object_emitSignal: Emitting signal id 0, with message 'value1'
server:value_object_emitSignal: Emitting signal id 2, with message 'value1'
method return sender=:1.38 -> dest=:1.42
下面看看修改另外一个变量的值 (double) ,有什么样的反应 :
[sbox-CHINOOK_X86: ~/glib-dbus-signals] > run-standalone.sh dbus-send /
 --type=method_call --print-reply --dest=org.maemo.Platdev_ex /
 /GlobalValue org.maemo.Value.setvalue2 double:100.5 // 这个double型被截断处理为100,所以这里只有一个信号发出
server:value_object_setvalue2: Called (valueIn=100.500)
server:value_object_emitSignal: Emitting signal id 1, with message 'value2'
method return sender=:1.38 -> dest=:1.44
[sbox-CHINOOK_X86: ~/glib-dbus-signals] > run-standalone.sh dbus-send /
 --type=method_call --print-reply --dest=org.maemo.Platdev_ex /
 /GlobalValue org.maemo.Value.setvalue2 double:101 // 这里会发送两个信号
server:value_object_setvalue2: Called (valueIn=101.000)
server:value_object_emitSignal: Emitting signal id 1, with message 'value2'
server:value_object_emitSignal: Emitting signal id 3, with message 'value2'
method return sender=:1.38 -> dest=:1.45
另外,你可能也注意到:在 server 侧发射信号后,并没有去跟踪这个信号是否被送出去了,这是因为 dbus-send 这个工具并不监听信号。有个工具可以跟踪这样的信号: dbus-monitor, 后面再讲如何跟踪。
 
Client 侧如何捕获信息?
      为了在 client 侧接收到 D-Bus 的信号,我们需要针对每个信号做大量的工作。因为 dbus-binding-tool 这个工具并部位信号生成任何代码(目前如此 , 2008.1.30 )。
在实现信号的回调时,需要仔细处理原型函数。这个原型函数需要的参数:
1 这里,我们的信号能发送一个字串,所以其对应的回调函数要至少有能接收字串的参数,
2 回调函数还要有个 proxy 对象参数,就是这个对象来接收信号的
3 用户数据,这个可选
下面是信号回调的具体实现:
/**
 * Signal handler for the "changed" signals. These will be sent by the
 * Value-object whenever its contents change (whether within
 * thresholds or not).
 *
 * Like before, we use strcmp to differentiate between the two
 * values, and act accordingly (in this case by retrieving
 * synchronously the values using getvalue1 or getvalue2.
 *
 * NOTE: Since we use synchronous getvalues, it is possible to get
 *       this code stuck if for some reason the server would be stuck
 *       in an eternal loop.
 */
static void valueChangedSignalHandler(
DBusGProxy* proxy,     // 接收信号的对象实例
const char* valueName, // 接收的参数
gpointer userData      // 用户自定义数据
)
{
 /* Since method calls over D-Bus can fail, we'll need to check
     for failures. The server might be shut down in the middle of
     things, or might act badly in other ways. */
 GError* error = NULL;
 
 g_print(PROGNAME ":value-changed (%s)/n", valueName);
 
 /* Find out which value changed, and act accordingly. */
  /* server 端哪个值发生了改变,client端就去读取哪个值 */
 if (strcmp(valueName, "value1") == 0) {
    gint v = 0;
    /* Execute the RPC to get value1. */
    org_maemo_Value_getvalue1(proxy, &v, &error);
    if (error == NULL) {
      g_print(PROGNAME ":value-changed Value1 now %d/n", v);
    } else {
      /* You could interrogate the GError further, to find out exactly
         what the error was, but in our case, we'll just ignore the
         error with the hope that some day (preferably soon), the
         RPC will succeed again (server comes back on the bus). */
      handleError("Failed to retrieve value1", error->message, FALSE);
    }
 } else {
    gdouble v = 0.0;
    org_maemo_Value_getvalue2(proxy, &v, &error);
    if (error == NULL) {
      g_print(PROGNAME ":value-changed Value2 now %.3f/n", v);
    } else {
      handleError("Failed to retrieve value2", error->message, FALSE);
    }
 }
 /* Free up error object if one was allocated. */
 g_clear_error(&error);
}
 
Client 侧注册信号分两步走:首先注册我们感兴趣的 D-Bus 信号;然后为该 D-Bus 信号对应的 Glib 信号注册一个回调函数,我们在主函数中做:
/**
 * The test program itself.
 *
 * 1) Setup GType/GSignal
 * 2) Create GMainLoop object
 * 3) Connect to the Session D-Bus
 * 4) Create a proxy GObject for the remote Value object
 * 5) Register signals that we're interested from the Value object
 * 6) Register signal handlers for them
 * 7) Start a timer that will launch timerCallback once per second.
 * 8) Run main-loop (forever)
 */
int main(int argc, char** argv) {
 
 /*... Listing cut for brevity ...*/
 
 remoteValue =
    dbus_g_proxy_new_for_name(bus,
                              VALUE_SERVICE_NAME, /* name */
                              VALUE_SERVICE_OBJECT_PATH, /* obj path */
                              VALUE_SERVICE_INTERFACE /* interface */);
 if (remoteValue == NULL) {
    handleError("Couldn't create the proxy object",
                "Unknown(dbus_g_proxy_new_for_name)", TRUE);
 }
 
 /* Register the signatures for the signal handlers.
     In our case, we'll have one string parameter passed to use along
     the signal itself. The parameter list is terminated with
     G_TYPE_INVALID (i.e., the GType for string objects. */
 
 g_print(PROGNAME ":main Registering signal handler signatures./n");
 
 /* Add the argument signatures for the signals (needs to be done
     before connecting the signals). This might go away in the future,
     when the GLib-bindings will do automatic introspection over the
     D-Bus, but for now we need the registration phase. */
 { /* Create a local scope for variables. */
 
    int i;
    const gchar* signalNames[] = { SIGNAL_CHANGED_VALUE1,
                                   SIGNAL_CHANGED_VALUE2,
                                   SIGNAL_OUTOFRANGE_VALUE1,
                                   SIGNAL_OUTOFRANGE_VALUE2 };
    /* Iterate over all the entries in the above array.
       The upper limit for i might seem strange at first glance,
       but is quite common idiom to extract the number of elements
       in a statically allocated arrays in C.
       NOTE: The idiom will not work with dynamically allocated
             arrays. (Or rather it will, but the result is probably
             not what you expect.) */
    for (i = 0; i < sizeof(signalNames)/sizeof(signalNames[0]); i++) {
      /* Since the function doesn't return anything, we cannot check
         for errors here. */
      // 注册Glib信号,这个函数内部完成了D-Bus信号 ß à Glib 信号的转换,
      dbus_g_proxy_add_signal(/* Proxy to use */
                              remoteValue,
                              /* Signal name */
                              signalNames[i],//Glib 信号
                              /* Will receive one string argument */
                              G_TYPE_STRING,
                              /* Termination of the argument list */
                             G_TYPE_INVALID);
    }
 } /* end of local scope */
 
 g_print(PROGNAME ":main Registering D-Bus signal handlers./n");
 
 /* We connect each of the following signals one at a time,
     since we'll be using two different callbacks. */
 // 给信号注册对应的回调函数。
 /* Again, no return values, cannot hence check for errors. */
 dbus_g_proxy_connect_signal(/* Proxy object */
                              remoteValue,
                              /* Signal name */
                              SIGNAL_CHANGED_VALUE1,
                              /* Signal handler to use. Note that the
                                 typecast is just to make the compiler
                                 happy about the function, since the
                                 prototype is not compatible with
                                 regular signal handlers. */
                              G_CALLBACK(valueChangedSignalHandler),
                              /* User-data (we don't use any). */
                              NULL,
                              /* GClosureNotify function that is
                                 responsible in freeing the passed
                                 user-data (we have no data). */
                              NULL);
 
 dbus_g_proxy_connect_signal(remoteValue, SIGNAL_CHANGED_VALUE2,
                              G_CALLBACK(valueChangedSignalHandler),
                              NULL, NULL);
 
 dbus_g_proxy_connect_signal(remoteValue, SIGNAL_OUTOFRANGE_VALUE1,
                              G_CALLBACK(outOfRangeSignalHandler),
                              NULL, NULL);
 
 dbus_g_proxy_connect_signal(remoteValue, SIGNAL_OUTOFRANGE_VALUE2,
                              G_CALLBACK(outOfRangeSignalHandler),
                              NULL, NULL);
 
 /* All signals are now registered and we're ready to handle them. */
 
 g_print(PROGNAME ":main Starting main loop (first timer in 1s)./n");
 
 /* Register a timer callback that will do RPC sets on the values.
     The userdata pointer is used to pass the proxy object to the
     callback so that it can launch modifications to the object. */
 g_timeout_add(1000, (GSourceFunc)timerCallback, remoteValue);
 
 /* Run the program. */
 g_main_loop_run(mainloop);
 /* Since the main loop is not stopped (by this code), we shouldn't
     ever get here. The program might abort() for other reasons. */
 
 /* If it does, return failure as exit code. */
 return EXIT_FAILURE;
}
 
      当用函数 dbus_g_proxy_add_signal 给信号填充参数时,要仔细点检查参数列表:信号参数的类型要和 server 侧要严格一致。对于回调函数也是一样,参数不匹配的话,肯定出错。
编译 client 侧,然后运行,看看效果:
[sbox-CHINOOK_X86: ~/glib-dbus-signals] > run-standalone.sh ./client
client:main Connecting to Session D-Bus.
client:main Creating a GLib proxy object for Value.
client:main Registering signal handler signatures.
client:main Registering D-Bus signal handlers.
client:main Starting main loop (first timer in 1s).
server:value_object_setvalue1: Called (valueIn=-80)
server:value_object_emitSignal: Emitting signal id 0, with message 'value1'
client:timerCallback Set value1 to -80
server:value_object_setvalue2: Called (valueIn=-120.000)
server:value_object_emitSignal: Emitting signal id 1, with message 'value2'
server:value_object_emitSignal: Emitting signal id 3, with message 'value2'
client:timerCallback Set value2 to -120.000
client:value-changed (value1)
server:value_object_getvalue1: Called (internal value1 is -80)
client:value-changed Value1 now -80
client:value-changed (value2)
server:value_object_getvalue2: Called (internal value2 is -120.000)
client:value-changed Value2 now -120.000
client:out-of-range (value2)!
client:out-of-range Value 2 is outside threshold
server:value_object_setvalue1: Called (valueIn=-70)
server:value_object_emitSignal: Emitting signal id 0, with message 'value1'
client:timerCallback Set value1 to -70
server:value_object_setvalue2: Called (valueIn=-110.000)
server:value_object_emitSignal: Emitting signal id 1, with message 'value2'
server:value_object_emitSignal: Emitting signal id 3, with message 'value2'
client:timerCallback Set value2 to -110.000
client:value-changed (value1)
server:value_object_getvalue1: Called (internal value1 is -70)
client:value-changed Value1 now -70
client:value-changed (value2)
server:value_object_getvalue2: Called (internal value2 is -110.000)
client:value-changed Value2 now -110.000
...
    上面部分被标志为蓝色的,都是 client 侧的回调函数打印的。
      Client 侧还启动了一个 1 秒的定时器,这个定时器主要是用于调用远程函数,修改 server 侧的对象的 value1 vaule2 的值。 Server 侧的值一旦发生改变或者值越界,就会发信号给 client ,通知 client 侧, client 侧的信号回调函数可以取得 server 侧被修改的值。这种来回关系,就是典型的 client/server 形式。
 
跟踪 D-Bus 信号:
    有时候,查看 bus 通道内到底携带了哪些信号是很有用的,特别是当我们给不知哪个接口发出来的信号注册回调时。 Dbus-monitor 可以附着到 D-Bus deamon 进程中,然后查看信号,并且把结果报告为 dbus-monitor ,它可以自动解析信号。
当上面的 client server 程序仍然在运行时,下面我们启动 dbus-monitor 看看,信号的传递情况:
[sbox-CHINOOK_X86: ~/glib-dbus-signals] > run-standalone.sh dbus-monitor type='signal'
signal sender=:1.38 -> dest=(null destination)
 inter member=changed_value1
 string "value1"
signal sender=:1.38 -> dest=(null destination)
 inter member=changed_value2
 string "value2"
signal sender=:1.38 -> dest=(null destination)
 inter member=outofrange_value2
 string "value2"
signal sender=:1.38 -> dest=(null destination)
 inter member=changed_value1
 string "value1"
signal sender=:1.38 -> dest=(null destination)
 inter member=changed_value2
 string "value2"
signal sender=:1.38 -> dest=(null destination)
 inter member=outofrange_value2
 string "value2"
signal sender=:1.38 -> dest=(null destination)
 inter member=changed_value1
 string "value1"
signal sender=:1.38 -> dest=(null destination)
 inter member=changed_value2
 string "value2"
signal sender=:1.38 -> dest=(null destination)
 inter member=changed_value1
 string "value1"
signal sender=:1.38 -> dest=(null destination)
 inter member=changed_value2
 string "value2"
还可以监视 system bus:
Nokia-N810-42-18:~# run-standalone.sh dbus-monitor --system
signal sender=:1.3 -> dest=(null destination) path=/com/nokia/mce/signal;
 inter member=display_status_ind
 string "dimmed"
signal sender=:1.3 -> dest=(null destination) path=/com/nokia/mce/signal;
 inter member=system_inactivity_ind
 boolean true
signal sender=:1.3 -> dest=(null destination) path=/com/nokia/mce/signal;
 inter member=save_unsaved_data_ind
signal sender=:1.3 -> dest=(null destination) path=/com/nokia/mce/signal;
 inter member=display_status_ind
 string "off"
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值