27
2017
09

OpenWrt源码分析之libubox

json

OpenWrt支持c、shell、lua三种语言的进程通过ubus进行进程间通讯,ubus通讯的消息格式遵循json格式。

json(JavaScript object Notation)是一种轻量级的数据交换格式,易于人读写,也易于机器解析和生成。json是一种独立于编程语言之外的文本格式,兼容多种编程语言,如c、c++、Java、JavaScript、perl、Python等。

json由两种格式组成:

  1. string
    格式是key:value,value为字符串;
    object是一个name/vale对,格式是{name:value},相当于c语言中的结构体、哈希表等。

  2. number
    格式是key:value,value为整数;

  3. boolean
    格式是key:value,value为1或者0;

  4. object
    object相当于c语言中中的结构体,格式是key:{key1:value1,key2:value2,…},value可以是string、number、boolean、object或者array;

  5. array
    array相当于c语言中的数组,格式是key:[value1,value2,…],value可以是string、number、boolean、object或者array。

OpenWrt shell程序中用到了命令jshn和脚本jshn.sh;
下面是一个shell程序中使用json的例子:

. /usr/share/libubox/jshn.sh

# generating json data
json_init
json_add_string "str" "Hello, world!"
json_add_object "obj"
json_add_int "num" "100"
json_add_boolean "bool" "0"
json_close_object
json_add_array "array"
json_add_string "arraystr" "array string"
json_add_int "" "110"
json_add_boolean "" "1"
json_close_array
MSG=`json_dump`
echo ${MSG}

# parsing json data
json_load "$MSG"
json_get_var varstr str
json_select obj
json_get_var varnum num
json_get_var varbool bool
json_select ..
json_select array
json_get_var array1 "1"
json_get_var array2 "2"
json_get_var array3 "3"
cat << EOF
{
  msg : $varstr,
  obj: {
      num : $varnum,
      bool : $varbool },
  array: [ $array1, $array2, $array3 ]
}

执行结果为:

root@OpenWrt:/# ./jsontest.sh
{ "str": "Hello, world!", "obj": { "num": 100, "bool": false }, "array": [ "array string", 110, true ] }
{
  msg : Hello, world!,
  obj: {
      num : 100,
      bool : 0 },
  array: [ array string, 110, 1 ]
}

shell json相关的api函数有:

函数 描述
json_init
json_cleanup
初始化json环境
清空json环境
json_add_string 添加string类型的element
json_add_int 添加int类型的element
json_add_boolean 添加boolean类型的element
json_add_table
json_close_table
添加table类型的element
json_add_array
json_close_array
添加array类型的element
json_load 从字符串中导入到json格式
json_select 进入到某个element,必须有是table或array才能使用json_select
json_get_keys 获取所有element的key
json_get_values 获取所有element的value
json_get_var 根据key获取value
json_get_type 获取element的类型

blob & blobmsg

ubus之间传递的消息在程序中使用blob或者blobmsg的形式组织,blob是一种二进制字节序列,在libubox中,blob使用结构体struct blob_attr表示,如下所示:

struct blob_attr {
    uint32_t id_len;
    char data[];
};

在内存中,一个blob数据的格式如下所示:
这里写图片描述

blob是符合TLV格式的,TLV表示Type-Length-Value,上图中,ID即使Type,Len即是Length,Payload即是Value。

blobmsg是在blob的基础上扩展出来的,blobmsg的格式如下图所示:
这里写图片描述

blobmsg中扩展标准位extended等于1,payload拆分出key和value两个字段,ID表示blogmsg的类型,类型包括BLOBMSG_TYPE_STRING、BLOBMSG_TYPE_INT、BLOBMSG_TYPE_BOOL、BLOBMSG_TYPE_TABLE、BLOBMSG_TYPE_ARRAY。

  • string、int、bool类型blobmsg
    类似于json,string类型的blobmsg的格式如下:
    这里写图片描述
    string类型的blobmsg的value为string,int和bool类型的blobmsg的value为对应类型的值。

  • table、array类型blobmsg
    类似于json,table类型的blobmsg相当于object类型的json,相当于c语言中的结构体,array相当于c语言中的数组;
    table类型的blobmsg格式如下图所示:
    这里写图片描述
    array类型的blobmsg格式如下图所示:
    这里写图片描述
    array和table十分相似,区别在于array的元素是不需要key名字的。

一般使用结构体blob_buf来表示blobmsg链表,blob_buf的head和buf(之所以要用两个指针是因为在加到blobmsg长度时,重新申请连续内存指针会发生改变)都指向一个table类型的blobmsg,buflen等于总长度;
格式如下所示:

blob或者blobmsg常用的api如下所示:

  • string
    blobmsg_add_string
    blobmsg_get_string

  • int
    blobmsg_add_u8
    blobmsg_add_u16
    blobmsg_add_u32
    blobmsg_add_u64
    blobmsg_get_u8
    blobmsg_get_u16
    blobmsg_get_u32
    blobmsg_get_u64

  • bool
    bool转换成u8的0或者1

  • table
    blobmsg_open_table
    blobmsg_close_table

/*
 * Example:
 *
 * table_key : {
 *     string_key : "this is a string",
 *     int_key : 100,
 *     bool_key : true
 */}
static struct blob_buf buf;
blobmsg_buf_init(&buf);
void *tbl = blobmsg_open_table(buf, "table_key");
blobmsg_add_string(buf, "string_key", "this is a string");
blobmsg_add_u8(buf, "int_key", 100);
blobmsg_add_u8(buf, "bool_key", 1);
blobmsg_close_table(buf, tbl);
  • array
    blobmsg_open_array
    blobmsg_close_array
/* * Example: * * array_key : [ "this is a string", 100, true ] */
static struct blob_buf buf;
blobmsg_buf_init(&buf);
void *array = blobmsg_open_array(buf, "array_key");
blobmsg_add_string(buf, NULL, "this is a string");
blobmsg_add_u8(buf, NULL, 100);
blobmsg_add_u8(buf, NULL, 1);
blobmsg_close_array(buf, array);
  • parse
    blobmsg_parse
//上面两个例子中添加table和array到buf中去,下面将其取出来
enum {
        FOO_TABLE,
        FOO_ARRAY
};
static const struct blobmsg_policy pol[] = {
        [FOO_TABLE] = {
                .name = "table_key",
                .type = BLOBMSG_TYPE_TABLE,
        },
        [FOO_ARRAY] = {
                .name = "array_key",
                .type = BLOBMSG_TYPE_ARRAY,
        },
};
struct blob_attr *tb[ARRAY_SIZE(pol)];
blobmsg_parse(pol, ARRAY_SIZE(pol), tb, blob_data(buf->head); //parse
/* after parse * tb[FOO_TABLE] is table blobmsg * tb[FOO_ARRAY] is array blobmsg * blobmsg_data(tb[FOO_TABLE] get table element head * __blob_for_each_attr(attr, head, len) get every element * /
上一篇:自定义Drawable实现圆形和圆角Drawable 下一篇:Android 8.0 新特性(三) - 自动调整TextView