大部分内容来自libubox [3] - BLOB BLOGMSG,推荐阅读原文。

blob提供二进制数据处理能力。有几种支持的数据类型,并可以创建块数据在socket上发送。整型数字会在libubox库内部转换为网络字节序进行处理。

二进制块的处理方法是创建一个TLV(类型-长度-值)链表数据,支持嵌套类型数据,并提供设置和获取数据接口。blob定义在blob.h中。

blogmsg位于blob的上层,提供表格和数组等数据类型的处理,定义在blogmsg.h中。

TLV是用于表示可变长度的数据格式,Type表示数据的类型,length表示数据长度,value存储数据值。类型和长度的占用空间是固定的,在libubox库中共占用4个字节。

Value的长度由length指定。这样可以存储和传输任何类型的数据,只需预先定义服务器和客户端之间的TLV的类型和长度的空间大小即可。

一. blob

blob(binary large object),二进制大对象,用于二进制对象序列化;blob主要在一些系统级组件(ubox/libubox/ubus/netifd)内部使用,一般应用不需要使用blob封装,blob用数据结构blob_attr表示。

blob_buf用于管理(多个)二进制大对象。

1. 数据结构

#define BLOB_COOKIE     0x01234567

enum {
BLOB_ATTR_UNSPEC,
BLOB_ATTR_NESTED,
BLOB_ATTR_BINARY,
BLOB_ATTR_STRING,
BLOB_ATTR_INT8,
BLOB_ATTR_INT16,
BLOB_ATTR_INT32,
BLOB_ATTR_INT64,
BLOB_ATTR_LAST
}; #define BLOB_ATTR_ID_MASK 0x7f000000
#define BLOB_ATTR_ID_SHIFT 24
#define BLOB_ATTR_LEN_MASK 0x00ffffff
#define BLOB_ATTR_ALIGN 4 //blob字节对齐
#define BLOB_ATTR_EXTENDED 0x80000000

// blob数据结构
struct blob_attr {
uint32_t id_len; //id占用最高字节,msb用于扩展,len占用低3个字节
char data[];
} __packed; // 属性过滤
struct blob_attr_info {
unsigned int type;
unsigned int minlen;
unsigned int maxlen;
bool (*validate)(const struct blob_attr_info *, struct blob_attr *);
};

// 多个blob管理数据结构
struct blob_buf {
struct blob_attr *head; // 指向blob_buf的开头,分配一个4字节的blob_attr(仅有id_len),记录已使用的len。最初时等于blob_buf->buf
bool (*grow)(struct blob_buf *buf, int minlen); //内存扩展回调函数
int buflen; //buf总长度
void *buf; // 指向buf起始位置(开头)
};

2. 函数

获取blob属性

/**
* 返回指向BLOB属性数据区指针
*/
static inline void * blob_data(const struct blob_attr *attr) /**
* 返回BLOB属性ID
*/
static inline unsigned int blob_id(const struct blob_attr *attr) /**
* 判断BLOB属性扩展标志是否为真
*/
static inline bool blob_is_extended(const struct blob_attr *attr) /**
* 返回BLOB属性有效存储空间大小
*/
static inline unsigned int blob_len(const struct blob_attr *attr) /*
* 返回BLOB属性完全存储空间大小(包括头部)
*/
static inline unsigned int blob_raw_len(const struct blob_attr *attr) /*
* 返回BLOB属性填补后存储空间大小(包括头部),存储空间补齐大小
*/
static inline unsigned int blob_pad_len(const struct blob_attr *attr)
{
    unsigned int len = blob_raw_len(attr);
    len = (len + BLOB_ATTR_ALIGN - 1) & ~(BLOB_ATTR_ALIGN - 1);
    return len;
}

获取blob数据

static inline uint8_t blob_get_u8(const struct blob_attr *attr)

static inline uint16_t blob_get_u16(const struct blob_attr *attr)

static inline uint32_t blob_get_u32(const struct blob_attr *attr)

static inline uint64_t blob_get_u64(const struct blob_attr *attr)

static inline int8_t blob_get_int8(const struct blob_attr *attr)

static inline int16_t blob_get_int16(const struct blob_attr *attr)

static inline int32_t blob_get_int32(const struct blob_attr *attr)

static inline int64_t blob_get_int64(const struct blob_attr *attr)

static inline const char * blob_get_string(const struct blob_attr *attr)

设置blob数据

static inline struct blob_attr *
blob_put_string(struct blob_buf *buf, int id, const char *str) static inline struct blob_attr *
blob_put_u8(struct blob_buf *buf, int id, uint8_t val) static inline struct blob_attr *
blob_put_u16(struct blob_buf *buf, int id, uint16_t val) static inline struct blob_attr *
blob_put_u32(struct blob_buf *buf, int id, uint32_t val) static inline struct blob_attr *
blob_put_u64(struct blob_buf *buf, int id, uint64_t val) #define blob_put_int8 blob_put_u8
#define blob_put_int16 blob_put_u16
#define blob_put_int32 blob_put_u32
#define blob_put_int64 blob_put_u64
/**
* ptr - 指向struct blob_attr
*/
struct blob_attr * blob_put(struct blob_buf *buf, int id, const void *ptr, unsigned int len)  

struct blob_attr * blob_put_raw(struct blob_buf *buf, const void *ptr, unsigned int len)

遍历

static inline struct blob_attr *
blob_next(const struct blob_attr *attr)
{
    return (struct blob_attr *) ((char *) attr + blob_pad_len(attr));
} #define __blob_for_each_attr(pos, attr, rem) \
for (pos = (void *) attr; \
rem > && (blob_pad_len(pos) <= rem) && \
(blob_pad_len(pos) >= sizeof(struct blob_attr)); \
rem -= blob_pad_len(pos), pos = blob_next(pos)) #define blob_for_each_attr(pos, attr, rem) \
for (rem = attr ? blob_len(attr) : , \
pos = attr ? blob_data(attr) : ; \
rem > && (blob_pad_len(pos) <= rem) && \
(blob_pad_len(pos) >= sizeof(struct blob_attr)); \
rem -= blob_pad_len(pos), pos = blob_next(pos))

复制

extern struct blob_attr *blob_memdup(struct blob_attr *attr);

嵌套

extern void *blob_nest_start(struct blob_buf *buf, int id);
extern void blob_nest_end(struct blob_buf *buf, void *cookie);

判断

bool blob_check_type(const void *ptr, unsigned int len, int type);
bool blob_attr_equal(const struct blob_attr *a1, const struct blob_attr *a2);

初始化和销毁

blob_buf一般声明为本地静态变量,id一般使用0(BLOBMSG_TYPE_UNSPEC)来初始化。

/**
* 初始化BLOB buffer
*/
int blob_buf_init(struct blob_buf *buf, int id) /**
* 销毁BLOB buffer
*/
void blob_buf_free(struct blob_buf *buf)

解析blob

/**
* 从attr串中根据info策略过滤,得到的结果存储在data属性数组中
*
* @param attr 输入BLOB属性串
* @param data 输出BLOB属性数组
* @param info 属性过滤策略
* @param max data数组大小
*/
int blob_parse(struct blob_attr *attr, struct blob_attr **data,
const struct blob_attr_info *info, int max)

二. blobmsg

blobmsg用于二进制对象网络序列化。嵌套在blob数据结构(blob_attr)的data区。因此形成:blob_buff <- blob_attr -< blobmsg,blob_buff可存储管理多个blob_attr,每个blob_attr又可存储管理一个blogmsg。且可存储在线性数据区,不需要链表指针。

blobmsg_policy用于解析和缓存blobmsg列表,一般声明为一个静态数组,用于指导消息解析。

blobmsg默认使用id为table。array类似C语言的数组,table类似C的结构。

1. 数据结构

#define BLOBMSG_ALIGN   2
#define BLOBMSG_PADDING(len) (((len) + (1 << BLOBMSG_ALIGN) - 1) & ~((1 << BLOBMSG_ALIGN) - 1)) enum blobmsg_type {
BLOBMSG_TYPE_UNSPEC,
BLOBMSG_TYPE_ARRAY,
BLOBMSG_TYPE_TABLE,
BLOBMSG_TYPE_STRING,
BLOBMSG_TYPE_INT64,
BLOBMSG_TYPE_INT32,
BLOBMSG_TYPE_INT16,
BLOBMSG_TYPE_INT8,
__BLOBMSG_TYPE_LAST,
BLOBMSG_TYPE_LAST = __BLOBMSG_TYPE_LAST - ,
BLOBMSG_TYPE_BOOL = BLOBMSG_TYPE_INT8,
}; struct blobmsg_hdr {
uint16_t namelen;
uint8_t name[];
} __packed;

// 解析blobmsg列表
struct blobmsg_policy {
const char *name; // 与blobmsg_hdr->name对应
enum blobmsg_type type; // 策略值的类型,数据打包解包时作为blob_attr id
};

2. 获取blogmsg属性

/**
* 根据BLOB消息名字长度计算出blobmsg头部大小
*/
static inline int blobmsg_hdrlen(unsigned int namelen) /**
* 获取BLOB消息名字
*/
static inline const char *blobmsg_name(const struct blob_attr *attr) /**
* 获取BLOB消息类型
*/
static inline int blobmsg_type(const struct blob_attr *attr) /**
* 获取BLOB消息数据内容
*/
static inline void *blobmsg_data(const struct blob_attr *attr) /**
* 获取BLOB消息数据内容大小
*/
static inline int blobmsg_data_len(const struct blob_attr *attr)
{
    uint8_t *start, *end;     start = (uint8_t *) blob_data(attr);
    end = (uint8_t *) blobmsg_data(attr);     return blob_len(attr) - (end - start);
}
static inline int blobmsg_len(const struct blob_attr *attr)
{
    return blobmsg_data_len(attr);
}

3. 数据类型判断

/**
* 判断BLOBMSG属性类型是否合法
*/
bool blobmsg_check_attr(const struct blob_attr *attr, bool name)

4. 设置

int blobmsg_add_field(struct blob_buf *buf, int type, const char *name,
const void *data, unsigned int len) static inline int
blobmsg_add_u8(struct blob_buf *buf, const char *name, uint8_t val) static inline int
blobmsg_add_u16(struct blob_buf *buf, const char *name, uint16_t val) static inline int
blobmsg_add_u32(struct blob_buf *buf, const char *name, uint32_t val) static inline int
blobmsg_add_u64(struct blob_buf *buf, const char *name, uint64_t val) static inline int
blobmsg_add_string(struct blob_buf *buf, const char *name, const char *string) static inline int
blobmsg_add_blob(struct blob_buf *buf, struct blob_attr *attr) /**
* 格式化设备BLOGMSG
*/
void blobmsg_printf(struct blob_buf *buf, const char *name, const char *format, ...)

5. 获取

static inline uint8_t blobmsg_get_u8(struct blob_attr *attr)
static inline bool blobmsg_get_bool(struct blob_attr *attr)
static inline uint16_t blobmsg_get_u16(struct blob_attr *attr)
static inline uint32_t blobmsg_get_u32(struct blob_attr *attr)
static inline uint64_t blobmsg_get_u64(struct blob_attr *attr)
static inline char *blobmsg_get_string(struct blob_attr *attr)

6. 创建

/**
* 创建BLOBMSG,返回数据区开始地址
*/
void *blobmsg_alloc_string_buffer(struct blob_buf *buf, const char *name, unsigned int maxlen) /**
* 扩大BLOGMSG,返回数据区开始地址
*/
void *blobmsg_realloc_string_buffer(struct blob_buf *buf, unsigned int maxlen) void blobmsg_add_string_buffer(struct blob_buf *buf)

7. 遍历

#define blobmsg_for_each_attr(pos, attr, rem) \
for (rem = attr ? blobmsg_data_len(attr) : , \
pos = attr ? blobmsg_data(attr) : ; \
rem > && (blob_pad_len(pos) <= rem) && \
(blob_pad_len(pos) >= sizeof(struct blob_attr)); \
rem -= blob_pad_len(pos), pos = blob_next(pos))

8. 嵌套

static inline void * blobmsg_open_array(struct blob_buf *buf, const char *name)
static inline void blobmsg_close_array(struct blob_buf *buf, void *cookie) static inline void *blobmsg_open_table(struct blob_buf *buf, const char *name)
static inline void blobmsg_close_table(struct blob_buf *buf, void *cookie)

9. 解析blogmsg

/**
* 从data BLOGMSG串中根据policy策略过滤,得到的结果存储在tb BLOGATTR数组中
*
* @param policy 过滤策略
* @param policy_len 策略个数
* @param tb 返回属性数据
* @param len data属性个数
*/
int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len,
struct blob_attr **tb, void *data, unsigned int len)

blobmsg根节点是一个纯粹的blob,所以blobmsg解析时需要注意:
(1)第一层解析,data必须取值为blob_data(root_blob),len必须取值为blob_len(root_blob)
(2)第二层及以上解析,data必须取值为blobmsg_data(sub_blob),len必须取值为blobmsg_data_len(sub_blob)
所以,应避免混合使用blob和blobmsg语义,比如第一层使用blob语义,第二层使用blobmsg语义。

三. blobmsg_json

blobmsg_json用于json对象的序列化,json提供脚本级消息发送机制,如果应用需要脚本配合,则需要使用json。

四. 示例

UCI配置文件: /etc/config/test

config policy test
option name 'test'
option enable ''
option dns '1.1.1.1 2.2.2.2'

定义参数列表

enum {
POLICY_ATTR_NAME, /** name */
POLICY_ATTR_ENABLE, /** enable */
POLICY_ATTR_DNS, /** dns */
__POLICY_ATTR_MAX
}; static const struct blobmsg_policy policy_attrs[__POLICY_ATTR_MAX] = {
[POLICY_ATTR_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
[POLICY_ATTR_ENABLE] = { .name = "enable", .type = BLOBMSG_TYPE_BOOL },
[POLICY_ATTR_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY },
}; /** 定义BLOBMSG_TYPE_ARRAY类型参数的实际数据类型 */
static const struct uci_blob_param_info policy_attr_info[__POLICY_ATTR_MAX] = {
[POLICY_ATTR_DNS] = { .type = BLOBMSG_TYPE_STRING },
}; static const struct uci_blob_param_list policy_attr_list = {
.n_params = __POLICY_ATTR_MAX,
.params = policy_attrs,
.info = policy_attr_info,
};

转化为blob

static struct uci_context *g_uci_ctx;
static struct blob_buf *b; void
transform(const char *config)
{
struct uci_context *ctx = g_uci_ctx;
struct uci_package *p = NULL; if (!ctx) {
ctx = uci_alloc_context();
g_uci_ctx = ctx;
uci_set_confdir(ctx, NULL);
} else {
p = uci_lookup_package(ctx, config);
if (p)
uci_unload(ctx, p);
} if (uci_load(ctx, config, &p))
return; struct uci_element *e;
struct blob_attr *config = NULL;
uci_foreach_element(&p->sectons, e) {
struct uci_section *s = uci_to_section(e); blob_buf_init(&b, );
uci_to_blob(&b, s, &policy_attr_list);
config = blob_memdup(b.head); /**
* do something with `config`
* free(config), when not use it
*/
}
}

使用转换后的blob

void
foo(blob_attr *confg)
{
struct blob_attr *tb[__POLICY_ATTR_MAX]; blobmsg_parse(policy_attrs, __POLICY_ATTR_MAX, tb,
blob_data(config), blob_len(config)); /**
* do something with *tb[]
*/
}

libubox-blob/blobmsg的更多相关文章

  1. libubox组件(2)——blob/blobmsg (转载 https://segmentfault.com/a/1190000002391970)

    一:blob相关接口 1.数据结构 1: struct blob_attr { 2: uint32_t id_len; /** 高1位为extend标志,高7位存储id, 3: * 低24位存储dat ...

  2. libubox

    lbubox是openwrt的一个核心库,封装了一系列基础实用功能,主要提供事件循环,二进制格式处理,linux链表实现和一些JSON辅助处理. 它的目的是以动态链接库方式来提供可重用的通用功能,给其 ...

  3. BLOB二进制对象(blob.c/h)

    BLOB二进制对象(blob.c/h) 数据结构 struct blob_attr { uint32_t id_len; /** 高1位为extend标志,高7位存储id, * 低24位存储data的 ...

  4. Oracle Blob数据保存为文件

    好久不写文,最近得空写一点.Oracle数据库国内用户量主要在企业上,其中有一种byte的存储称为Blob,并不能直接看. 有时候为了调试需要,可以通过: ,)) ; 这种sql去转为字符串查看,但是 ...

  5. [HTML5] Blob对象

    写在前面 本篇主要总结Blob对象属性及作用,通过DEMO介绍Blob对象的应用场景. Blob对象 一直以来,JS都没有比较好的可以直接处理二进制的方法.而Blob的存在,允许我们可以通过JS直接操 ...

  6. 【转】Caffe初试(八)Blob,Layer和Net以及对应配置文件的编写

    深度网络(net)是一个组合模型,它由许多相互连接的层(layers)组合而成.Caffe就是组建深度网络的这样一种工具,它按照一定的策略,一层一层的搭建出自己的模型.它将所有的信息数据定义为blob ...

  7. https://github.com/chenghuige/tensorflow-exp/blob/master/examples/sparse-tensor-classification/

        https://github.com/chenghuige/tensorflow-exp/blob/master/examples/sparse-tensor-classification/ ...

  8. <十>JDBC_处理Blob类型数据

    /*  * 读取BLOB数据:  *  使用getBlob方法读取到Blob对象  *  调用Blob的getBinaryStream(方法得到输入流,在使用IO操作  * */ @Test publ ...

  9. oracle--导出、导入blob类型的字段

    blob是oracle中的一个数据类型,保存的是压缩后的二进制形式的大数据. 数据迁移如果涉及到blob字段,都不好处理,因为无法用常规方法进行操作,如:使用select查看该字段,也无法用inser ...

随机推荐

  1. 基于QTP的自己主动化測试框架介绍

    继前面用了七章介绍了基于QTP的自己主动化測试框架,以下再用几个视频再补充一下.        视频一:基本框架特点介绍说明 .框架的特点从正反两面进行了分析以及主要思想      http://v. ...

  2. Java笔记16:多线程共享数据

    一.Thread实现 public class ThreadDemo4 { publicstaticvoid main(String[] args) { new ThreadTest4().start ...

  3. (转)MySQL的JDBC驱动源码解析

    一.背景 MySQL是一个中小型关系型数据库管理系统,目前我们淘宝也使用的也非常广泛.为了对开发中间DAO持久层的问题能有更深的理解以及最近在使用的phoenix on Hbase的SQL也是实现的J ...

  4. (转)如何将本地git仓库中的代码上传到github

    1,  在github上新建一个仓库,比如为:CSS3Test,仓库地址为:https://github.com/hyuanyuanlisiwei/CSS3Test 2,本地git仓库中的文件项目为C ...

  5. An incompatible version 1.1.14 of APR based Apache Tomcat Native library is installed, while Tomcat

    启动tomcat 7.0, 看到日志里出现严重警告, An incompatible version 1.1.14 of APR based Apache Tomcat Native library ...

  6. 通过NAT实例实现外部访问AWS的ElastiCache资源

    ElastiCache作为AWS的内存缓存组建可以说做的一点也不友好了, 你可以通过ElastiCache创建redis,memcache的实例,却不能被外部访问. 背景 人傻钱多的客户总有人傻钱多的 ...

  7. 倍福TwinCAT(贝福Beckhoff)常见问题(FAQ)-点击激活配置进入到运行模式直接死机或蓝屏怎么办

    下载我提供的TCRtime.sys文件,替换掉TwinCAT/Driver目录下的原有文件(原有文件要小一点,这个是159KB的) 如果你同时也安装了TwinCAT3,请不要替换这个,他是398KB的 ...

  8. 获取当前View

    在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById().不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例 ...

  9. javascript-使用el表达式获取后台传递的数据

      js获取后台数据 CreateTime--2017年5月26日16:14:14Author:Marydon 在js中使用el表达式的前提是:HTML引用js使用内联方式(即在JSP页面内部使用js ...

  10. (一)Lucene——基本概念介绍

    1. Lucene是什么 Lucene 是一个基于 Java 的全文信息检索工具包,它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能.Lucene 目前是 Apache Jakart ...