libubox-blob/blobmsg
大部分内容来自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的更多相关文章
- 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 ...
- libubox
lbubox是openwrt的一个核心库,封装了一系列基础实用功能,主要提供事件循环,二进制格式处理,linux链表实现和一些JSON辅助处理. 它的目的是以动态链接库方式来提供可重用的通用功能,给其 ...
- BLOB二进制对象(blob.c/h)
BLOB二进制对象(blob.c/h) 数据结构 struct blob_attr { uint32_t id_len; /** 高1位为extend标志,高7位存储id, * 低24位存储data的 ...
- Oracle Blob数据保存为文件
好久不写文,最近得空写一点.Oracle数据库国内用户量主要在企业上,其中有一种byte的存储称为Blob,并不能直接看. 有时候为了调试需要,可以通过: ,)) ; 这种sql去转为字符串查看,但是 ...
- [HTML5] Blob对象
写在前面 本篇主要总结Blob对象属性及作用,通过DEMO介绍Blob对象的应用场景. Blob对象 一直以来,JS都没有比较好的可以直接处理二进制的方法.而Blob的存在,允许我们可以通过JS直接操 ...
- 【转】Caffe初试(八)Blob,Layer和Net以及对应配置文件的编写
深度网络(net)是一个组合模型,它由许多相互连接的层(layers)组合而成.Caffe就是组建深度网络的这样一种工具,它按照一定的策略,一层一层的搭建出自己的模型.它将所有的信息数据定义为blob ...
- https://github.com/chenghuige/tensorflow-exp/blob/master/examples/sparse-tensor-classification/
https://github.com/chenghuige/tensorflow-exp/blob/master/examples/sparse-tensor-classification/ ...
- <十>JDBC_处理Blob类型数据
/* * 读取BLOB数据: * 使用getBlob方法读取到Blob对象 * 调用Blob的getBinaryStream(方法得到输入流,在使用IO操作 * */ @Test publ ...
- oracle--导出、导入blob类型的字段
blob是oracle中的一个数据类型,保存的是压缩后的二进制形式的大数据. 数据迁移如果涉及到blob字段,都不好处理,因为无法用常规方法进行操作,如:使用select查看该字段,也无法用inser ...
随机推荐
- 基于QTP的自己主动化測试框架介绍
继前面用了七章介绍了基于QTP的自己主动化測试框架,以下再用几个视频再补充一下. 视频一:基本框架特点介绍说明 .框架的特点从正反两面进行了分析以及主要思想 http://v. ...
- Java笔记16:多线程共享数据
一.Thread实现 public class ThreadDemo4 { publicstaticvoid main(String[] args) { new ThreadTest4().start ...
- (转)MySQL的JDBC驱动源码解析
一.背景 MySQL是一个中小型关系型数据库管理系统,目前我们淘宝也使用的也非常广泛.为了对开发中间DAO持久层的问题能有更深的理解以及最近在使用的phoenix on Hbase的SQL也是实现的J ...
- (转)如何将本地git仓库中的代码上传到github
1, 在github上新建一个仓库,比如为:CSS3Test,仓库地址为:https://github.com/hyuanyuanlisiwei/CSS3Test 2,本地git仓库中的文件项目为C ...
- 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 ...
- 通过NAT实例实现外部访问AWS的ElastiCache资源
ElastiCache作为AWS的内存缓存组建可以说做的一点也不友好了, 你可以通过ElastiCache创建redis,memcache的实例,却不能被外部访问. 背景 人傻钱多的客户总有人傻钱多的 ...
- 倍福TwinCAT(贝福Beckhoff)常见问题(FAQ)-点击激活配置进入到运行模式直接死机或蓝屏怎么办
下载我提供的TCRtime.sys文件,替换掉TwinCAT/Driver目录下的原有文件(原有文件要小一点,这个是159KB的) 如果你同时也安装了TwinCAT3,请不要替换这个,他是398KB的 ...
- 获取当前View
在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById().不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例 ...
- javascript-使用el表达式获取后台传递的数据
js获取后台数据 CreateTime--2017年5月26日16:14:14Author:Marydon 在js中使用el表达式的前提是:HTML引用js使用内联方式(即在JSP页面内部使用js ...
- (一)Lucene——基本概念介绍
1. Lucene是什么 Lucene 是一个基于 Java 的全文信息检索工具包,它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能.Lucene 目前是 Apache Jakart ...