linux 进程间通信 dbus-glib【实例】详解一(附代码)(d-feet工具使用)

linux 进程间通信 dbus-glib【实例】详解二(上) 消息和消息总线(附代码)

linux 进程间通信 dbus-glib【实例】详解二(下) 消息和消息总线(ListActivatableNames和服务器的自动启动)(附代码)

linux 进程间通信 dbus-glib【实例】详解三(下) 数据类型和dteeth(类型签名type域)(层级结构:服务Service --> Node(对象、object) 等 )(附代码)

linux 进程间通信 dbus-glib【实例】详解四(上) C库 dbus-glib 使用(附代码)(编写接口描述文件.xml,dbus-binding-tool工具生成绑定文件)

文章目录

  • dbus实例讲解(四上):使用dbus-glib
  • 1、接口
    • 1.1、编写接口描述文件
    • 1.2、由接口描述文件生成绑定文件
  • 2 对象
    • 2.1 对象定义
    • 2.2 信号的列集函数
    • 2.3 对象实现
  • 3 主程序
    • 3.1 登记dbus服务器
    • 3.2 IO Channel
    • 3.3 编译运行

dbus实例讲解(四上):使用dbus-glib

dbus-glib是dbus底层接口的一个封装。本讲我们用dbus-glib做一个dus接口,并写一个客户程序。

1、接口

1.1、编写接口描述文件

首先编写接口描述文件。我们要实现的连接的公共名是"org.freesmartphone.ogsmd",接口描述文件如下:

$ cat smss.xml
<?xml version="1.0" encoding="UTF-8" ?><node name="/org/freesmartphone/GSM/Device"><interface name="org.freesmartphone.GSM.SMS"><method name="SendMessage"><arg name="number" type="s"/><arg name="contents" type="s"/><arg name="featuremap" type="a{sv}"/><arg type="i" direction="out"/></method><signal name="IncomingMessage"><arg name="address" type="s"/><arg name="contents" type="s"/><arg name="features" type="a{sv}"/></signal></interface>
</node>

我们要在连接"org.freesmartphone.ogsmd"中的实现对象"/org/freesmartphone/GSM/Device"。 这个对象有接口"org.freesmartphone.GSM.SMS"。这个接口有一个SendMessage方法和一个IncomingMessage信号。

SendMessage方法和IncomingMessage信号除了两个字符串参数外,还有一个a{sv}参数,这是一个哈希表,即python的字典。 键-值对的键类型是字符串,值类型是VARIANT。这个接口是openmoko fso接口的一部分。 但为简单起见,本例在哈希表部分,只用三个键值。

键"alphabet"对应的值类型是字符串。
键"csm_num"对应的值类型是INT32。
键"csm_seq"对应的值类型是INT32。
请注意方法和信号名应采用单词连写,首字母大写的格式。

1.2、由接口描述文件生成绑定文件

有一个叫dbus-binding-tool的工具,它读入接口描述文件,产生一个绑定文件。这个文件包含了dbus对象的接口信息。 在主程序中我们通过dbus_g_object_type_install_info函数向dbus-glib登记对象信息(DBusGObjectInfo结构)。

本例使用了autotool,在Makefile.am中可以这样调用dbus-binding-tool:

smss-glue.h: smss.xml

$(LIBTOOL) --mode=execute dbus-binding-tool --prefix=gsm_sms --mode=glib-server --output=smss-glue.h $(srcdir)/smss.xml

"--prefix"参数定义了对象前缀。设对象前缀是$(prefix),则生成的DBusGObjectInfo结构变量名就是dbus_glib_$(prefix)_object_info。 绑定文件会为接口方法定义回调函数。回调函数的名称是这样的:首先将xml中的方法名称转换到全部小写,下划线分隔的格式,然后增加前缀"$(prefix)_"。 例如:如果xml中有方法SendMessage,绑定文件就会引用一个名称为$(prefix)_send_message的函数。

绑定文件还会为接口方法生成用于散集(Unmarshaling)(反序列化?)的函数。在dbus消息中,方法参数是以流格式存在的。 该函数将方法参数由数据流还原到glib的数据格式,并传入方法的回调函数。 本例中,dbus-binding-tool生成以下的smss-glue.h:

Dontla:先照着前面创建smss.xml文件,然后我在ubuntu上终端执行:dbus-binding-tool --mode=glib-server --prefix=gsm_sms smss.xml>smss-glue.h
参照:https://dontla.blog.csdn.net/article/details/122531787

(smss-glue.h)

/* Generated by dbus-binding-tool; do not edit! */#ifndef __dbus_glib_marshal_gsm_sms_MARSHAL_H__
#define __dbus_glib_marshal_gsm_sms_MARSHAL_H__#include <glib-object.h>G_BEGIN_DECLS#ifdef G_ENABLE_DEBUG
#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
#define g_marshal_value_peek_char(v)     g_value_get_schar (v)
#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
#define g_marshal_value_peek_int(v)      g_value_get_int (v)
#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
#define g_marshal_value_peek_long(v)     g_value_get_long (v)
#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
#define g_marshal_value_peek_float(v)    g_value_get_float (v)
#define g_marshal_value_peek_double(v)   g_value_get_double (v)
#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
#define g_marshal_value_peek_param(v)    g_value_get_param (v)
#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
#define g_marshal_value_peek_object(v)   g_value_get_object (v)
#define g_marshal_value_peek_variant(v)  g_value_get_variant (v)
#else /* !G_ENABLE_DEBUG */
/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.*          Do not access GValues directly in your code. Instead, use the*          g_value_get_*() functions*/
#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
#define g_marshal_value_peek_char(v)     (v)->data[0].v_int
#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
#define g_marshal_value_peek_long(v)     (v)->data[0].v_long
#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
#define g_marshal_value_peek_float(v)    (v)->data[0].v_float
#define g_marshal_value_peek_double(v)   (v)->data[0].v_double
#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
#define g_marshal_value_peek_variant(v)  (v)->data[0].v_pointer
#endif /* !G_ENABLE_DEBUG *//* BOOLEAN:STRING,STRING,BOXED,POINTER,POINTER */
extern void dbus_glib_marshal_gsm_sms_BOOLEAN__STRING_STRING_BOXED_POINTER_POINTER (GClosure     *closure,GValue       *return_value,guint         n_param_values,const GValue *param_values,gpointer      invocation_hint,gpointer      marshal_data);
void
dbus_glib_marshal_gsm_sms_BOOLEAN__STRING_STRING_BOXED_POINTER_POINTER (GClosure     *closure,GValue       *return_value G_GNUC_UNUSED,guint         n_param_values,const GValue *param_values,gpointer      invocation_hint G_GNUC_UNUSED,gpointer      marshal_data)
{typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_STRING_BOXED_POINTER_POINTER) (gpointer     data1,gpointer     arg_1,gpointer     arg_2,gpointer     arg_3,gpointer     arg_4,gpointer     arg_5,gpointer     data2);GMarshalFunc_BOOLEAN__STRING_STRING_BOXED_POINTER_POINTER callback;GCClosure *cc = (GCClosure*) closure;gpointer data1, data2;gboolean v_return;g_return_if_fail (return_value != NULL);g_return_if_fail (n_param_values == 6);if (G_CCLOSURE_SWAP_DATA (closure)){data1 = closure->data;data2 = g_value_peek_pointer (param_values + 0);}else{data1 = g_value_peek_pointer (param_values + 0);data2 = closure->data;}callback = (GMarshalFunc_BOOLEAN__STRING_STRING_BOXED_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback);v_return = callback (data1,g_marshal_value_peek_string (param_values + 1),g_marshal_value_peek_string (param_values + 2),g_marshal_value_peek_boxed (param_values + 3),g_marshal_value_peek_pointer (param_values + 4),g_marshal_value_peek_pointer (param_values + 5),data2);g_value_set_boolean (return_value, v_return);
}G_END_DECLS#endif /* __dbus_glib_marshal_gsm_sms_MARSHAL_H__ */#include <dbus/dbus-glib.h>
static const DBusGMethodInfo dbus_glib_gsm_sms_methods[] = {{ (GCallback) gsm_sms_send_message, dbus_glib_marshal_gsm_sms_BOOLEAN__STRING_STRING_BOXED_POINTER_POINTER, 0 },
};const DBusGObjectInfo dbus_glib_gsm_sms_object_info = {  1,dbus_glib_gsm_sms_methods,1,
"org.freesmartphone.GSM.SMS\0SendMessage\0S\0number\0I\0s\0contents\0I\0s\0featuremap\0I\0a{sv}\0arg3\0O\0F\0N\0i\0\0\0",
"org.freesmartphone.GSM.SMS\0IncomingMessage\0\0",
"\0"
};

在包含绑定文件前,我们必须声明绑定文件要引用的回调函数。(什么意思?)

2 对象

2.1 对象定义

dbus-glib用GObject实现dbus对象。所以我们首先要实现一个对象。在本例中,我们实现一个GsmSms对象,它继承了GObject:

(gsm_sms.h)

$ cat gsm_sms.h
#ifndef GSM_SMS_H
#define GSM_SMS_Htypedef struct GsmSms GsmSms;
typedef struct GsmSmsClass GsmSmsClass;struct GsmSms
{GObject parent;
};struct GsmSmsClass
{GObjectClass parent;
};#define GSM_SMS_TYPE                  (gsm_sms_get_type ())GType gsm_sms_get_type (void);
gboolean gsm_sms_send_message (GsmSms *obj, const char *number, const char *contents, GHashTable *featuremap, int *ret, GError **error);
void gsm_sms_emit_incoming_message(GsmSms *obj, const char * address, const char * contents, GHashTable *hash);#endif

GObject的对象定义虽然繁琐,但有固定的套路。依样画葫芦,画多了就习惯了。我们在gsm_sms.h中声明了gsm_sms_send_message函数。 gsm_sms_send_message函数是在gsm_sms.c中实现的,在绑定文件smss-glue.h中用到。 因为主程序要使用绑定文件中的对象信息,所以应由主程序包含绑定文件。 主程序只要在包含绑定文件前包含gsm_sms.h,编译器就不会抱怨gsm_sms_send_message函数未声明。

2.2 信号的列集函数

列集(Marshaling)是将数据从某种格式存为流格式的操作;散集(Unmarshaling)则是列集的反操作,将信息从流格式中还原出来。 在绑定文件中,dbus-binding-tool自动生成函数将方法参数从dbus消息中还原出来,即实现了散集。 那么我们怎么把信号参数由glib的数据结构转换到消息中的数据流呢?

因为GsmSms对象有一个信号,所以在对象类初始化函数gsm_sms_class_init中,我们要调用g_signal_new创建信号。 g_signal_new要求我们提供一个列集函数。

glib有一些标准的列集函数,在gmarshal.h中定义。例如g_cclosure_marshal_VOID__STRING,这个函数适合只有一个字符串参数的信号。 如果gmarshal.h没有提供适合的列集函数,我们可以用一个叫glib-genmarshal的工具自动生成列集函数。 后面我们会看到,无论是标准列集函数还是生成的列集函数都是既可以用于列集也可以用于散集,这些函数通常都被称作列集函数

使用glib-genmarshal前,我们同样要准备一个输入文件:

$ cat sms-marshal.list
# see glib-genmarshal(1) for a detailed description of the file format,
# possible parameter types are:
#   VOID        indicates   no   return   type,  or  no  extra
#               parameters. if VOID is used as  the  parameter
#               list, no additional parameters may be present.
#   BOOLEAN     for boolean types (gboolean)
#   CHAR        for signed char types (gchar)
#   UCHAR       for unsigned char types (guchar)
#   INT         for signed integer types (gint)
#   UINT        for unsigned integer types (guint)
#   LONG        for signed long integer types (glong)
#   ULONG       for unsigned long integer types (gulong)
#   ENUM        for enumeration types (gint)
#   FLAGS       for flag enumeration types (guint)
#   FLOAT       for single-precision float types (gfloat)
#   DOUBLE      for double-precision float types (gdouble)
#   STRING      for string types (gchar*)
#   PARAM       for GParamSpec or derived types  (GParamSpec*)
#   BOXED       for boxed (anonymous but reference counted) types (GBoxed*)
#   POINTER     for anonymous pointer types (gpointer)
#   OBJECT      for GObject or derived types (GObject*)
#   NONE        deprecated alias for VOID
#   BOOL        deprecated alias for BOOLEAN
VOID:STRING,STRING,BOXED

我们需要的函数返回类型是VOID,参数是STRING,STRING,BOXED。在Makefile.am中可以这样调用glib-genmarshal:

sms-marshal.h: sms-marshal.list$(LIBTOOL) --mode=execute glib-genmarshal --header sms-marshal.list --prefix=sms_marshal > sms-marshal.hsms-marshal.c: sms-marshal.list$(LIBTOOL) --mode=execute glib-genmarshal --body sms-marshal.list --prefix=sms_marshal > sms-marshal.c

"--prefix"和函数原型决定输出函数名。如果"--prefix=sms_marshal",函数原型是"OID:STRING,STRING,BOXED", 生成的列集函数名就必然是sms_marshal_VOID__STRING_STRING_BOXED

在本例中自动生成的文件内容如下:

$ cat sms-marshal.h#ifndef __sms_marshal_MARSHAL_H__
#define __sms_marshal_MARSHAL_H__#include        <glib-object.h>G_BEGIN_DECLS/* VOID:STRING,STRING,BOXED (sms-marshal.list:24) */
extern void sms_marshal_VOID__STRING_STRING_BOXED (GClosure     *closure,GValue       *return_value,guint         n_param_values,const GValue *param_values,gpointer      invocation_hint,gpointer      marshal_data);G_END_DECLS#endif /* __sms_marshal_MARSHAL_H__ */$ cat sms-marshal.c#include        <glib-object.h>#ifdef G_ENABLE_DEBUG
#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
#define g_marshal_value_peek_char(v)     g_value_get_char (v)
#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
#define g_marshal_value_peek_int(v)      g_value_get_int (v)
#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
#define g_marshal_value_peek_long(v)     g_value_get_long (v)
#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
#define g_marshal_value_peek_float(v)    g_value_get_float (v)
#define g_marshal_value_peek_double(v)   g_value_get_double (v)
#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
#define g_marshal_value_peek_param(v)    g_value_get_param (v)
#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
#define g_marshal_value_peek_object(v)   g_value_get_object (v)
#else /* !G_ENABLE_DEBUG */
/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.*          Do not access GValues directly in your code. Instead, use the*          g_value_get_*() functions*/
#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
#define g_marshal_value_peek_char(v)     (v)->data[0].v_int
#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
#define g_marshal_value_peek_long(v)     (v)->data[0].v_long
#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
#define g_marshal_value_peek_float(v)    (v)->data[0].v_float
#define g_marshal_value_peek_double(v)   (v)->data[0].v_double
#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
#endif /* !G_ENABLE_DEBUG *//* VOID:STRING,STRING,BOXED (sms-marshal.list:24) */
void
sms_marshal_VOID__STRING_STRING_BOXED (GClosure     *closure,GValue       *return_value,guint         n_param_values,const GValue *param_values,gpointer      invocation_hint,gpointer      marshal_data)
{typedef void (*GMarshalFunc_VOID__STRING_STRING_BOXED) (gpointer     data1,gpointer     arg_1,gpointer     arg_2,gpointer     arg_3,gpointer     data2);register GMarshalFunc_VOID__STRING_STRING_BOXED callback;register GCClosure *cc = (GCClosure*) closure;register gpointer data1, data2;g_return_if_fail (n_param_values == 4);if (G_CCLOSURE_SWAP_DATA (closure)){data1 = closure->data;data2 = g_value_peek_pointer (param_values + 0);}else{data1 = g_value_peek_pointer (param_values + 0);data2 = closure->data;}callback = (GMarshalFunc_VOID__STRING_STRING_BOXED) (marshal_data ? marshal_data : cc->callback);callback (data1,g_marshal_value_peek_string (param_values + 1),g_marshal_value_peek_string (param_values + 2),g_marshal_value_peek_boxed (param_values + 3),data2);
}

2.3 对象实现

准备好列集函数后,我们来实现GsmSms。

$ cat -n gsm_sms.c1  #include <dbus/dbus-glib.h>2  #include <stdio.h>3  #include <stdlib.h>4  #include <string.h>5  #include "gsm_sms.h"6  #include "sms-marshal.h"7  #include "sms_features.h"89  enum10  {11      INCOMING_MESSAGE,12      LAST_SIGNAL13  };1415  static guint signals[LAST_SIGNAL];1617  G_DEFINE_TYPE(GsmSms, gsm_sms, G_TYPE_OBJECT)1819  static void gsm_sms_init (GsmSms *obj)20  {21  }2223  static void gsm_sms_class_init (GsmSmsClass *klass)24  {25      signals[INCOMING_MESSAGE] = g_signal_new (26          "incoming_message",27          G_OBJECT_CLASS_TYPE (klass),28          G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,29          0,30          NULL, NULL,31          sms_marshal_VOID__STRING_STRING_BOXED,32          G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING,33          sms_get_features_type());34  }3536  gboolean gsm_sms_send_message (GsmSms *obj, const char *number, const char *contents,37      GHashTable *featuremap, int *ret, GError **error)38  {39      printf("number=%s\n", number);40      printf("contents=%s\n", contents);41      sms_show_features(featuremap);42      *ret = strlen(contents);43      return TRUE;44  }4546  void gsm_sms_emit_incoming_message(GsmSms *obj, const char * address,47      const char * contents, GHashTable *hash)48  {49      g_signal_emit (obj, signals[INCOMING_MESSAGE], 0, address, contents, hash);50  }

在类初始化函数gsm_sms_class_init中,我们调用g_signal_new创建了信号。g_signal_new函数的原型是:

guint g_signal_new (const gchar *signal_name,GType itype,GSignalFlags signal_flags,guint class_offset,GSignalAccumulator accumulator,gpointer accu_data,GSignalCMarshaller c_marshaller,GType return_type,guint n_params,...);

31行提供了列集函数。32-33行是返回值类型和参数类型。其中第三个参数调用了函数sms_get_features_type(在sms_features.h中声明)。 因为a{sv}类型的参数处理起来比较繁琐,我专门写了一个sms_features模块处理,后面会介绍。

在主程序中登记对象信息时,对象信息把SendMessage方法和gsm_sms_send_message函数以及自动生成的散集函数联系起来。 当客户程序调用SendMessage方法时,dbus-glib会通过对象信息表格找到回调函数和散集函数, 用散集函数从method_call消息中取出参数传入回调函数gsm_sms_send_message。 gsm_sms_send_message调用sms_show_features函数处理a{sv}参数。 sms_show_features也在sms_features模块定义,后面会介绍。

gsm_sms模块提供了一个gsm_sms_emit_incoming_message函数供外部模块调用。 调用这个函数可以发射一个信号。在真实环境中,只有外部事件发生后才会发射信号。 本例中会有测试代码发射信号。

3 主程序

3.1 登记dbus服务器

下面就是主程序

$ cat -n smss.c1  #include <dbus/dbus-glib.h>2  #include <stdio.h>3  #include <stdlib.h>4  #include <glib/giochannel.h>5  #include "gsm_sms.h"6  #include "smss-glue.h"7  #include "sms_features.h"89  #define SMSS_DEBUG1011  static void lose (const char *str, ...)12  {13      va_list args;14      va_start (args, str);15      vfprintf (stderr, str, args);16      fputc ('\n', stderr);17      va_end (args);18      exit (1);19  }2021  static void lose_gerror (const char *prefix, GError *error)22  {23      if (error) {24          lose ("%s: %s", prefix, error->message);25      }26      else {27          lose ("%s", prefix);28      }29  }3031  static void shell_help(void)32  {33      printf( "\ts\tsend signal\n"34          "\tq\tQuit\n"35          );36  }3738  void emit_signal(GsmSms *obj)39  {40      GHashTable *features = sms_create_features("ucs2", 3, 1);41      gsm_sms_emit_incoming_message(obj, "12345678901", "hello signal!", features);42      sms_release_features(features);43  }4445  #define STDIN_BUF_SIZE    102446  static gboolean channel_cb(GIOChannel *source, GIOCondition condition, gpointer data)47  {48      int rc;49      char buf[STDIN_BUF_SIZE+1];50      GsmSms *obj = (GsmSms *)data;5152      if (condition != G_IO_IN) {53          return TRUE;54      }5556      /* we've received something on stdin.    */57      printf("# ");58      rc = fscanf(stdin, "%s", buf);59      if (rc <= 0) {60          printf("NULL\n");61          return TRUE;62      }6364      if (!strcmp(buf, "h")) {65          shell_help();66      } else if (!strcmp(buf, "?")) {67          shell_help();68      } else if (!strcmp(buf, "s")) {69          emit_signal(obj);70      } else if (!strcmp(buf, "q")) {71          exit(0);72      } else {73          printf("Unknown command `%s'\n", buf);74      }75      return TRUE;76  }7778  int main (int argc, char **argv)79  {80      DBusGConnection *bus;81      DBusGProxy *bus_proxy;82      GError *error = NULL;83      GsmSms *obj;84      GMainLoop *mainloop;85      guint request_name_result;86      GIOChannel *chan;8788  #ifdef SMSS_DEBUG89      g_slice_set_config(G_SLICE_CONFIG_ALWAYS_MALLOC, TRUE);90  #endif91      g_type_init ();9293      dbus_g_object_type_install_info (GSM_SMS_TYPE, &dbus_glib_gsm_sms_object_info);9495      mainloop = g_main_loop_new (NULL, FALSE);9697      bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);98      if (!bus)99          lose_gerror ("Couldn't connect to system bus", error);100101      bus_proxy = dbus_g_proxy_new_for_name (bus, "org.freedesktop.DBus",102          "/", "org.freedesktop.DBus");103104      if (!dbus_g_proxy_call (bus_proxy, "RequestName", &error,105          G_TYPE_STRING, "org.freesmartphone.ogsmd",106          G_TYPE_UINT, 0,107          G_TYPE_INVALID,108          G_TYPE_UINT, &request_name_result,109          G_TYPE_INVALID))110          lose_gerror ("Failed to acquire org.freesmartphone.ogsmd", error);111112      obj = g_object_new (GSM_SMS_TYPE, NULL);113      dbus_g_connection_register_g_object (bus, "/org/freesmartphone/GSM/Device", G_OBJECT (obj));114115      printf ("service is running\n");116      chan = g_io_channel_unix_new(0);117      g_io_add_watch(chan, G_IO_IN, channel_cb, obj);118      g_main_loop_run (mainloop);119120      exit (0);121  }

93行调用dbus_g_object_type_install_info登记GsmSms类的接口信息。97行连接会话总线。 101-102行在会话总线上为连接"org.freedesktop.DBus"的"/“对象的接口"org.freedesktop.DBus"建立代理。 104-109行通过接口代理调用"RequestName"方法,请求公共名"org.freesmartphone.ogsmd”。

请求公共名成功后,112行建立GsmSms对象。113行登记GsmSms对象,登记时指定对象路径"/org/freesmartphone/GSM/Device", 并传入对象指针。118行进入主循环等待客户消息。

3.2 IO Channel

我想增加一个敲键测试信号发射。但我又必须在glib主循环里等待dbus消息。怎样才能既等待dbus消息,又等待敲键呢? 这种情况可以使用glib的IO Channels。glib的IO Channels允许我们在glib主循环等待指定的文件或socket句柄。

要使用IO Channels,首先包含"glib/giochannel.h"。116行用句柄0(即标准输入)创建一个GIOChannel。 117行为我们创建的GIOChannel登记回调函数。我们在回调函数channel_cb中处理敲键,发射信号。

3.3 编译运行

读者可以从这里下载完整的示例程序。 下集会介绍本例的autotool工程。目前,我们先编译运行一下,解压后执行:

$ ./configure
$ make
$ cd src
$ ./smss
service is running
h
#       s       send signalq       Quit

键入h后回车,可以看到敲键的帮助信息。

我想找个客户程序测试一下,dbus-send不能发a{sv}这样复杂的参数。我们可以用d-feet测试,或者写个python脚本:

$ cat ./smsc.py
#!/usr/bin/env python
import dbus
bus=dbus.SessionBus()
bus_obj=bus.get_object('org.freesmartphone.ogsmd', '/org/freesmartphone/GSM/Device')
iface=dbus.Interface(bus_obj, 'org.freesmartphone.GSM.SMS')
ret=iface.SendMessage('1234567890', 'hello from python',
{'alphabet':'gsm','csm_num':8,'csm_seq':2})
print "SendMessage return %d" % (ret)

执行smsc.py,在服务器端看到:

$ ./smss
service is running
h
#       s       send signalq       Quit
number=1234567890
contents=hello from python
csm_num=8
alphabet=gsm
csm_seq=2

说明服务器可以正常工作。主程序的89行要求glib直接用malloc分配内存,这样用valgrind才能检查到内存泄漏(如果有的话)。 我们可以这样运行smss以检查是否有内存泄漏:

$ valgrind --tool=memcheck --leak-check=full ./smss

这一片看得我有一点懵逼,有些代码结构作者貌似没讲

参考文章:dbus实例讲解(四上):使用dbus-glib

linux 进程间通信 dbus-glib【实例】详解四(上) C库 dbus-glib 使用(附代码)(编写接口描述文件.xml,dbus-binding-tool工具生成绑定文件)(列集散集函数)相关推荐

  1. python中get函数是什么意思_详解python中get函数的用法(附代码)_后端开发

    strncmp函数用法详解_后端开发 strncmp函数为字符串比较函数,其函数语法为"int strncmp ( const char * str1, const char * str2, ...

  2. 每日一练:Python爬虫爬取全国新冠肺炎疫情数据实例详解,使用beautifulsoup4库实现

    Python 爬虫篇 - 爬取全国新冠肺炎疫情数据实例详解 效果图展示 第一章:疫情信息的下载与数据提取 ① 爬取页面数据到本地 ② json 字符串正则表达式分析 ③ 提取数据中的 json 字符串 ...

  3. 《Java和Android开发实战详解》——2.5节良好的Java程序代码编写风格

    本节书摘来自异步社区<Java和Android开发实战详解>一书中的第2章,第2.5节良好的Java程序代码编写风格,作者 陈会安,更多章节内容可以访问云栖社区"异步社区&quo ...

  4. 太酷了!Linux的30 个实例详解 TOP 命令!

    英文:Linoxide 编译:Linux中国/geekpilinux.cn/article-2352-1.html Linux中的top命令显示系统上正在运行的进程.它是系统管理员最重要的工具之一.被 ...

  5. 详解Python中get函数的用法(附代码)

    描述: Python 字典 get() 函数返回指定键的值,如果值不在字典中返回默认值. 语法: get()方法语法: dict.get(key, default=None) 参数: key – 字典 ...

  6. python中的get函数什么意思_详解python中get函数的用法(附代码)

    描述 Python 字典 get() 函数返回指定键的值,如果值不在字典中返回默认值. 语法 get()方法语法:dict.get(key, default=None) 参数 key – 字典中要查找 ...

  7. python get函数用法_详解python中get函数的用法(附代码)

    描述 Python 字典 get() 函数返回指定键的值,如果值不在字典中返回默认值. 语法 get()方法语法:dict.get(key, default=None) 参数 key – 字典中要查找 ...

  8. 青少年编程scratch一级-熟悉编程软件(答案及详解+线上题库答题)

    线上题库答题+自动评卷 https://blog.csdn.net/zhengzyx2040/article/details/118388826 scratch一级-熟悉编程软件试题 [熟悉编程软件] ...

  9. linux 进程间通信 dbus-glib【实例】详解三 数据类型和dteeth(类型签名type域)(层级结构:服务Service --> Node(对象、object) 等 )(附代码)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

最新文章

  1. Spring源码窥探之:xxxAware接口
  2. 区块链BaaS云服务(2)亚马逊 Amazon Managed Blockchain
  3. P4254-[JSOI2008]Blue Mary开公司【李超树】
  4. linux 硬盘空间监控,Linux服务器硬盘空间监控
  5. Keil 文本对不上格
  6. ASP.NET 2.0中使用自定义provider (2)
  7. oracle 查看动态性能视图,Oracle 中的V$ 动态性能视图
  8. python面试题之简要描述Python的垃圾回收机制(garbage collection)
  9. 基于selenium生成Csdn 博客文章简索的excel文件
  10. numpy 1.22.1 基本语法
  11. 初识Vocaloid3
  12. 一连三问 !!! 什么是内存对齐?内存对齐的原因是什么?内存对齐的好处是什么?
  13. oracle11g64位怎么用sql,plsql32 位连接oracle11g64位方法
  14. python爬虫中国土地市场网的相关数据最新2021/5/7
  15. 知识图谱 Freebase 的基本概念
  16. 【Java--名片管理系统】
  17. 天猫魔盒部分adb shell或telnet下有用命令
  18. Alkyne-PEG-Amine,Alkyne-PEG-NH2 炔基PEG氨基
  19. 短信验证码是什么?在网站中起到什么作用?
  20. 在线创建MySQL表

热门文章

  1. Python list(列表) 详细总结
  2. mysql 白皮书_mysql企业版 《 MySQL企业版中文白皮书 》.cn.doc
  3. 【ABAP】更新交货单交货数量和拣配数量
  4. 【Oracle】触发器最系统入门学习指导
  5. TSV_TNEW_PAGE_ALLOC_FAILED
  6. 如何做SEO项目管理?
  7. 更改记录表CDHDR和CDPOS
  8. SAP FICO与金蝶财务软件的区别
  9. 为什么手机垃圾就是治不了?
  10. SAP系统权限管理及参数设置