DBus glib 各数据类型接收与发送详解—C语言(3)

动机 前置知识 正文
Python 测试服务 使用 C 实现复杂数据类型的传递
DICT_DICT ObjectPath_Dict_Struct_Array C D-Bus 测试完整代码
Makefile

动机

说到 DBus 用过的人大概都能明白其工作的流程。典型的使用流程是,向 DBus 服务进程发送数据,然后接收其返回的数据。简单的说,就像调用函数一样,向服务进程发送数据就相当于函数的参数,其返回的数据就相当于函数返回的结果。虽然明白了流程,但想要使用 C语言 通过已有的 DBus 服务进行操作,仍然是一项不太容易的工作(对像我这样的菜鸟^_^),因为数据的类型真是太多了, 使用 Python 会简单一点。简单点的有 Boolean, Byte, Int32, Int64, String, ObjectPath, Signature 等; 复杂一点的有 Array, Struct, Dict 等。如果不能弄清楚它们之间的联系,那么将是一件非常头痛的事。为了使我研究的结果不被淡忘,于是有了这篇文章。

前置知识

  • 能够熟练使用 C语言;
  • 了解 DBus 各数据类型的表示, 参考 D-Bus Specification
  • 对 DBus-glib 有基本的了解,能够与 DBus 服务进程进行简单的交互。
  • 简单使用 d-feet, 参考 D-Bus 实例讲解
  • 大概对 Python 有些了解(只是为了说明我的分析思路,如果你只想找 C 的解决方法,那完全可以不了解);
  • 简单了解 python dbus

正文

上一篇讨论了高级数据类型的传递,这次我们就讨论更难一点的, 复杂数据类型 的传递。为什么说复杂呢?因为它是高级数据类型的杂揉,本来高级数据类型就挺难的了,再杂揉一下,不用活了。

同样先给出 Python 编写的服务与测试

Python DBus 服务进程

more_advanced_data_deliver_service.py

#!/usr/bin/env pythonimport gobjectimport dbus
import dbus.service
import dbus.mainloop.glibclass AdvancedData(dbus.service.Object):def __init__(self, bus, object_path):dbus.service.Object.__init__(self, bus, object_path)self._last_input = None@dbus.service.method('airead.fan.MoreAdvancedDataType', in_signature='a(si)', out_signature='a(si)')def StructArrayPrint(self, struct_array):print "receive struct array:"for st in struct_array:for value in st:print value, ",",print '\n' + '-' * 28print '=' * 33ret = [('li', 21), ('wen', 22), ('feng', 23)]return ret@dbus.service.method('airead.fan.MoreAdvancedDataType', in_signature='a{sv}', out_signature='a{sv}')def DictDictPrint(self, dictdict):print "receive dict{sv}:"for subdict in dictdict:print "subdict:", subdictfor key in dictdict[subdict]:print "    ", key, ":", dictdict[subdict][key]print '-' * 33print '=' * 33ret = {};ret['fanrenhao'] = {'name':'renhao', 'age':'24', 'gender': 'male'}ret['liwenfeng'] = {'name':'wenfeng', 'age':'22', 'gender': 'female'}return ret@dbus.service.method('airead.fan.MoreAdvancedDataType', in_signature='a(oa{sv})', out_signature='a(oa{sv})')def ObjectPathDictStructArrayPrint(self, complex_array):print "receive a(oa{sv}):"for struct in complex_array:for mem in struct:if type(mem) == dbus.Dictionary:for key in mem:print key, ":", mem[key]else:print memprint '-' * 33print '=' * 33# o for objectpatho1 = dbus.ObjectPath("/path1")o2 = dbus.ObjectPath("/path2")# d for dictionaryd1 = {'name':'renhao', 'age':24, 'gender': 'male'}d2 = {'name':'wenfeng', 'age':22, 'gender': 'female'}# s for structs1 = (o1, d1)s2 = (o2, d2)ret = [s1, s2]return retif __name__ == '__main__':dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)session_bus = dbus.SessionBus()name = dbus.service.BusName("airead.fan.MoreAdvancedDataType", session_bus)object = AdvancedData(session_bus, '/airead/fan/MoreAdvancedDataType')mainloop = gobject.MainLoop()print "Running example service."mainloop.run()

Python 测试服务

more_advanced_data_deliver_test_py.py

#!/usr/bin/pythonimport sys
import dbus
from traceback import print_excdef main():bus = dbus.SessionBus()try:remote_object = bus.get_object("airead.fan.MoreAdvancedDataType", "/airead/fan/MoreAdvancedDataType")dbus_interface = dbus.Interface(remote_object, "airead.fan.MoreAdvancedDataType")#test a(si)astruct = [('apple', 1), ('banana', 2), ('cherry', 5)]ret = dbus_interface.StructArrayPrint(astruct)print "receive struct array:"for struct in ret:for value in struct:print valueprint '-' * 28print '=' * 33 + "\n"#test a{sv}dic = {}dic['fanrenhao'] = {'name':'renhao', 'age':'24', 'gender': 'male'}dic['liwenfeng'] = {'name':'wenfeng', 'age':'22', 'gender': 'female'}ret = dbus_interface.DictDictPrint(dic)print "receive dict{sv}:"for subdict in ret:print "subdict:", subdictfor key in ret[subdict]:print "    ", key, ":", ret[subdict][key]print '-' * 33print '=' * 33 + "\n"#test a(oa{sv})# o for objectpatho1 = dbus.ObjectPath("/p1")o2 = dbus.ObjectPath("/p2")# d for dictionaryd1 = {'a':'apple', 'b': 'banana'}d2 = {'c': 'cherry', 'd': 88}complex_array = [(o1, d1), (o2, d2)]ret = dbus_interface.ObjectPathDictStructArrayPrint(complex_array)print "receive a(oa{sv}):"for struct in ret:for mem in struct:if type(mem) == dbus.Dictionary:for key in mem:print key, ":", mem[key]else:print memprint '-' * 33print '=' * 33 + "\n"except dbus.DBusException:print_exc()sys.exit(1)main()

使用 C 实现复杂数据类型的传递

以下代码仅仅为了演示数据类型的传递,不保证没有内存泄漏,请仔细检查后再使用。

STRUCT_ARRAY

这次我们要传递的是结构体数组 "a(si)"。

因为没有 "(si)" 类型,所以我们自己定义。同样因为没有 "a(si)",所以我们也自己定义。那么接下来如代码所示,就可以进行传递了。

只要知道哪种数据与哪种类型对应后,就不难了。难就难在不知道该与哪种数据类型对应,同时又对 dbus-glib 与 glib 不熟,这样的话,真的是比较头痛的一件事。

#define DBUS_STRUCT_STRING_INT (                         \dbus_g_type_get_struct ( "GValueArray", G_TYPE_STRING,  \G_TYPE_INT, G_TYPE_INVALID))
#define DBUS_ARRAY_STRUCT_STRING_INT ( \dbus_g_type_get_collection("GPtrArray", DBUS_STRUCT_STRING_INT) )int send_recv_struct_array(DBusGProxy *proxy)
{gchar *method;GError *error = NULL;GPtrArray *gparray, *ret;GValueArray *garray[3], *tmp_garray;GValue gval[3][2] = {`0`};GValue *tmp_gval;gchar *str[3] = {"apple", "banana", "cherry"};gint num[3] = {1, 2, 5};int i, j;for (i = 0; i < 3; i++) {g_value_init (&gval[i][0], G_TYPE_STRING);g_value_set_string(&gval[i][0], str[i]);g_value_init (&gval[i][1], G_TYPE_INT);g_value_set_int(&gval[i][1], num[i]);}gparray = g_ptr_array_new();for (i = 0; i < 3; i++) {garray[i] = g_value_array_new(0);for (j = 0; j < 2 ; j++) {g_value_array_append(garray[i], &gval[i][j]);}g_ptr_array_add(gparray, garray[i]);}method = "StructArrayPrint";if (!dbus_g_proxy_call(proxy, method, &error,DBUS_ARRAY_STRUCT_STRING_INT, gparray,G_TYPE_INVALID,DBUS_ARRAY_STRUCT_STRING_INT, &ret,G_TYPE_INVALID)) {g_printerr("call %s failed: %s\n", method, error->message);g_error_free(error);error = NULL;return -1;}for (i = 0; i < ret->len; i++) {tmp_garray = g_ptr_array_index(ret, i);tmp_gval = g_value_array_get_nth(tmp_garray, 0);g_print("%s: ", g_value_get_string(tmp_gval));tmp_gval = g_value_array_get_nth(tmp_garray, 1);g_print("%d\n", g_value_get_int(tmp_gval));}g_print("=================================\n\n");return 0;
}

DICT_DICT

下面演示的是一个 "a{sv}" 的数据类型,特别的是这里的 "v" 我们用它再来容纳一个 "a{ss}" 数据类型。这样的话是不是有点复杂了哇?

源代码如下,俗话说,源代码上没有任何能够隐藏的秘密,有这句话吧?

#define DBUS_TYPE_G_STRING_VALUE_HASHTABLE                             \dbus_g_type_get_map ( "GHashTable", G_TYPE_STRING, G_TYPE_VALUE)int send_recv_dictdict(DBusGProxy *proxy)
{int i;char *method;GHashTable *table, *ret, *subtable;GHashTableIter iter, subiter;gpointer key, value, subkey, subvalue;GError *error = NULL;GValue gval[2] = `0`;gchar *table_value[2][3] = {{"renhao", "24", "male"},{"wenfeng", "22", "female"}};table = g_hash_table_new(NULL, NULL);for (i = 0; i < 2; i++) {g_value_init(&gval[i], DBUS_TYPE_G_STRING_STRING_HASHTABLE);g_value_take_boxed(&gval[i],dbus_g_type_specialized_construct(DBUS_TYPE_G_STRING_STRING_HASHTABLE));subtable = g_value_get_boxed(&gval[i]);g_hash_table_insert(subtable, "name", table_value[i][0]);g_hash_table_insert(subtable, "age", table_value[i][1]);g_hash_table_insert(subtable, "gender", table_value[i][2]);}g_hash_table_insert(table, "fanrenhao", &gval[0]);g_hash_table_insert(table, "liwenfeng", &gval[1]);method = "DictDictPrint";if (!dbus_g_proxy_call(proxy, method, &error,DBUS_TYPE_G_STRING_VALUE_HASHTABLE, table,G_TYPE_INVALID,DBUS_TYPE_G_STRING_VALUE_HASHTABLE, &ret,G_TYPE_INVALID)) {g_printerr("call %s failed: %s\n", method, error->message);g_error_free(error);error = NULL;return -1;}g_print("receive: dictionary\n");g_hash_table_iter_init(&iter, ret);while (g_hash_table_iter_next(&iter, &key, &value)) {g_print("%s:\n", (char *)key);subtable = g_value_get_boxed(value);g_hash_table_iter_init(&subiter, subtable);while (g_hash_table_iter_next(&subiter, &subkey, &subvalue)) {g_print("%s, %s\n", (char *)subkey, (char *)subvalue);}g_print("---------------------------------\n");}g_print("=================================\n\n");return 0;
}

ObjectPath_Dict_Struct_Array

这是一个 "a(oa{sv})" 的数据类型。也就是说首先要定义一个 "a{sv}" 的数据类型, 再由 "a{sv}" 定义一个 "(oa{sv})",最后再定义 "a(oa{sv})" 的数据类型。这很复杂吧,现实中真的传递过这样复杂的数据吗? 真的出现过,就在 connman (connect manager 类似 network-manager 的东东) 的服务进程中! 我就是因为它才接触到了 D-Bus, 它的 "a(oa{sv})" 真的是害得我不浅,所以才有了这篇文章。

具体代码如下:

int send_recv_objectpath_dict_struct_array(DBusGProxy *proxy)
{//这个当成是期末考试的试题吧 ^_^//好吧,我承认是我懒了return 0;
}

C D-Bus 测试完整代码

/*** @file more_advanced_data_deliver_test_c.c* @brief* @author Airead Fan <fgh1987168@gmail.com>* @date 2012/03/23 17:55:41*/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dbus/dbus-glib.h>#define METHOD_STRLEN 128/** a{sv}* dic = {}* dic['fanrenhao'] = {'name':'renhao', 'age':'24', 'gender': 'male'}* dic['liwenfeng'] = {'name':'wenfeng', 'age':'22', 'gender': 'female'}*/#define DBUS_TYPE_G_STRING_VALUE_HASHTABLE                             \dbus_g_type_get_map ( "GHashTable", G_TYPE_STRING, G_TYPE_VALUE)int send_recv_dictdict(DBusGProxy *proxy)
{int i;char *method;GHashTable *table, *ret, *subtable;GHashTableIter iter, subiter;gpointer key, value, subkey, subvalue;GError *error = NULL;GValue gval[2] = `0`;gchar *table_value[2][3] = {{"renhao", "24", "male"},{"wenfeng", "22", "female"}};table = g_hash_table_new(NULL, NULL);for (i = 0; i < 2; i++) {g_value_init(&gval[i], DBUS_TYPE_G_STRING_STRING_HASHTABLE);g_value_take_boxed(&gval[i],dbus_g_type_specialized_construct(DBUS_TYPE_G_STRING_STRING_HASHTABLE));subtable = g_value_get_boxed(&gval[i]);g_hash_table_insert(subtable, "name", table_value[i][0]);g_hash_table_insert(subtable, "age", table_value[i][1]);g_hash_table_insert(subtable, "gender", table_value[i][2]);}g_hash_table_insert(table, "fanrenhao", &gval[0]);g_hash_table_insert(table, "liwenfeng", &gval[1]);method = "DictDictPrint";if (!dbus_g_proxy_call(proxy, method, &error,DBUS_TYPE_G_STRING_VALUE_HASHTABLE, table,G_TYPE_INVALID,DBUS_TYPE_G_STRING_VALUE_HASHTABLE, &ret,G_TYPE_INVALID)) {g_printerr("call %s failed: %s\n", method, error->message);g_error_free(error);error = NULL;return -1;}g_print("receive: dictionary\n");g_hash_table_iter_init(&iter, ret);while (g_hash_table_iter_next(&iter, &key, &value)) {g_print("%s:\n", (char *)key);subtable = g_value_get_boxed(value);g_hash_table_iter_init(&subiter, subtable);while (g_hash_table_iter_next(&subiter, &subkey, &subvalue)) {g_print("%s, %s\n", (char *)subkey, (char *)subvalue);}g_print("---------------------------------\n");}g_print("=================================\n\n");return 0;
}/** a(si)* astruct = [('apple', 1), ('banana', 2), ('cherry', 5)]*/#define DBUS_STRUCT_STRING_INT (                         \dbus_g_type_get_struct ( "GValueArray", G_TYPE_STRING,  \G_TYPE_INT, G_TYPE_INVALID))
#define DBUS_ARRAY_STRUCT_STRING_INT ( \dbus_g_type_get_collection("GPtrArray", DBUS_STRUCT_STRING_INT) )int send_recv_struct_array(DBusGProxy *proxy)
{gchar *method;GError *error = NULL;GPtrArray *gparray, *ret;GValueArray *garray[3], *tmp_garray;GValue gval[3][2] = {`0`};GValue *tmp_gval;gchar *str[3] = {"apple", "banana", "cherry"};gint num[3] = {1, 2, 5};int i, j;for (i = 0; i < 3; i++) {g_value_init (&gval[i][0], G_TYPE_STRING);g_value_set_string(&gval[i][0], str[i]);g_value_init (&gval[i][1], G_TYPE_INT);g_value_set_int(&gval[i][1], num[i]);}gparray = g_ptr_array_new();for (i = 0; i < 3; i++) {garray[i] = g_value_array_new(0);for (j = 0; j < 2 ; j++) {g_value_array_append(garray[i], &gval[i][j]);}g_ptr_array_add(gparray, garray[i]);}method = "StructArrayPrint";if (!dbus_g_proxy_call(proxy, method, &error,DBUS_ARRAY_STRUCT_STRING_INT, gparray,G_TYPE_INVALID,DBUS_ARRAY_STRUCT_STRING_INT, &ret,G_TYPE_INVALID)) {g_printerr("call %s failed: %s\n", method, error->message);g_error_free(error);error = NULL;return -1;}for (i = 0; i < ret->len; i++) {tmp_garray = g_ptr_array_index(ret, i);tmp_gval = g_value_array_get_nth(tmp_garray, 0);g_print("%s: ", g_value_get_string(tmp_gval));tmp_gval = g_value_array_get_nth(tmp_garray, 1);g_print("%d\n", g_value_get_int(tmp_gval));}g_print("=================================\n\n");return 0;
}int send_recv_objectpath_dict_struct_array(DBusGProxy *proxy)
{return 0;
}int main(int argc, char *argv[])
{DBusGConnection *connection;GError *error = NULL;DBusGProxy *proxy;g_type_init();/* conect system connection and get proxy */connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);if (connection == NULL) {g_printerr("get system bus failed: %s\n", error->message);g_error_free(error);return -1;}/* get proxy */proxy = dbus_g_proxy_new_for_name(connection,"airead.fan.MoreAdvancedDataType","/airead/fan/MoreAdvancedDataType","airead.fan.MoreAdvancedDataType");send_recv_dictdict(proxy);send_recv_struct_array(proxy);send_recv_objectpath_dict_struct_array(proxy);return 0;
}

Makefile

有些东西实际上没用,我也懒得去了。

CC    = gccCFLAGS    = -Wall -g
CFLAGS += $(shell pkg-config --cflags glib-2.0 )
CFLAGS += $(shell pkg-config --cflags dbus-glib-1)
#CFLAGS += $(shell pkg-config --cflags gtk+-2.0)LDFLAGS  =
LDFLAGS += $(shell pkg-config --libs glib-2.0)
LDFLAGS += $(shell pkg-config --libs dbus-glib-1)
#LDFLAGS += $(shell pkg-config --libs gtk+-2.0)SOURCE =  $(wildcard *.c)
TARGETS := $(patsubst %.c, %, $(SOURCE))
TARGETS_OUT = common_marshaler basic_data
TARGETS := $(filter-out $(TARGETS_OUT), $(TARGETS))
TARGETS := $(addsuffix .out, $(TARGETS))%.out: %.c@echo CC $< -o $@@$(CC) $< common_marshaler.c basic_data.c $(CFLAGS) -o $@ $(LDFLAGS).PHONY: all clean test marshalerall: $(TARGETS)marshaler:glib-genmarshal --prefix _common_marshal --header common_marshaler.list > common_marshaler.hglib-genmarshal --prefix _common_marshal --body common_marshaler.list > common_marshaler.cdbus-binding-tool --prefix=airead_fan --mode=glib-server all_basic_data_deliver_server.xml > all_basic_data_deliver_server.hclean:rm -f *~ a.out *.o $(TARGETS) core.*test:@echo TARGETS: $(TARGETS)

转载于:https://blog.51cto.com/fanrenhao/817627

DBus glib 各数据类型接收与发送详解—C语言(3)相关推荐

  1. FPGA串口接收与发送详解( part 3 )

    之前的part1~2已经详解完了单个数据的串口接收与发送,链接如下: FPGA串口接收与发送 详解 (part 1 )_居安士的博客-CSDN博客 FPGA串口接收与发送详解( part 2 )_居安 ...

  2. TX2/Linux下can总线的接收与发送详解!(回环测试)

    https://blog.csdn.net/hhlenergystory/article/details/81976069 TX2具有两个can设备,分别为can0和can1.这两个can设备自带ca ...

  3. C#串口连接的读取和发送详解

    C#串口连接的读取和发送详解 一.串口连接的打开与关闭 串口,即COM口,在.NET中使用 SerialPort 类进行操作.串口开启与关闭,是涉及慢速硬件的IO操作,频繁打开或关闭会影响整体处理速度 ...

  4. java原生类型没有封装_Java基本数据类型与封装类型详解(int和Integer区别)

    Java基本数据类型与封装类型详解(int和Integer区别) 发布于 2020-4-19| 复制链接 摘记: int是java提供的8种原始数据类型之一.Java为每个原始类型提供了封装类,Int ...

  5. java 封装表单数据类型_Java基本数据类型与封装类型详解(int和Integer区别)

    int是java提供的8种原始数据类型之一. Java为每个原始类型提供了封装类,Integer是java为int提供的封装类(即Integer是一个java对象,而int只是一个基本数据类型).in ...

  6. MySQL数据类型以及基本使用详解

    MySQL数据类型以及基本使用详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.MySQL服务器的主要组件 我们知道MySQL的主要组件主要是由服务端(mysqld)和客户端 ...

  7. python numpy dtype object_关于Numpy数据类型对象(dtype)使用详解

    常用方法 #记住引入numpy时要是用别名np,则所有的numpy字样都要替换 #查询数值类型 >>>type(float) dtype('float64') # 查询字符代码 &g ...

  8. php 微信 公众 平台,微信公众平台代码详解-php语言(一)

    2.这里把它粘贴出来,以注释的形式进行讲解. 3.首先我们要知道一些基础的知识: (1)要有自己的网站--公网环境,其中一个php页面处理微信消息: (2)微信公众平台和网站服务器之间是通过XML数据 ...

  9. 详解c语言编程库题,详解C语言编程

    C语言作为编程语言,其诞生已经很早,但是在编程语言多样化的今天,C仍然高居TIOBE编程语言排行榜的第一位(2014年5月),而C++语言排位第四.而位居第二位的Java本身就是脱胎于C++语言,第三 ...

最新文章

  1. 宏基因组报名倒计时!报名线上课还可免费参加线下课
  2. 数字三角形路径最小值c语言题目,算法学习——动态规划之点数值三角形的最小路径...
  3. python学了有什么用处-Python主要用途是哪些,跟机器学习等有啥关系呢?
  4. [MATLAB调试笔记]Update magnetic field in one step
  5. MySQL索引与Index Condition Pushdown(二)
  6. Flink之状态之状态存储 state backends
  7. 【转】一、用于VS2019的QT配置
  8. sgm3157功能_SGM3157_SGM3157供应商_价格_Datasheet_pdf资料-IC资料网
  9. HALCON学习之旅(二)
  10. Navicat连接mysql8.0.1版本出现1251--Client does not support authentication protocol requested by server的解决
  11. Midletinfo-探索手机javaME系统信息的实用工具
  12. 【转载】GIS概念解析:大地高 | 海拔 | 正高 | 正常高
  13. 计算机系毕业论文绪论,本科毕业论文绪论范文
  14. 关于手心输入法配置完整自然码辅码
  15. [转] 测度论简介------一个通往异世界的大门
  16. 用requests库和BeautifulSoup4库爬取新闻列表
  17. oracle audit_actions,Oracle Audit 功能的使用和说明
  18. Socket的超时时间
  19. APP_ALLOW_MISSING_DEPS :=true
  20. hdu 1677 Nested Dolls 子串

热门文章

  1. IIS 使用OpenSSL 生成的自签名证书,然后使用SingalR 客户端访问Https 站点通信
  2. activeMq初识 - 2
  3. Windows单机配置Kafka环境
  4. SQL Server 2008 R2的发布订阅配置实践
  5. 关于Adium近期无法添加MSN联系人的说明
  6. 数据库连接配置策略和实践
  7. Flex itemRenderer 内联渲染器
  8. 推荐系统算法-Apriori
  9. yum安装apache及问题解决
  10. 'weblogic.kernel.Default (self-tuning) 问题weblogic层面解决办法