json-c-0.9库解析
- 预备知识
项目中使用json格式字符串进行进程间通信,使用json-c-0.9库进行字符串解析和设置,现将json-c-0.9库进行说明,欢迎指正~~
1. 编译
- ./configure CC= –host= –prefix=PATH
指定编译器、主机类型、安装路径(绝对路径),默认路径/usr/local - make && make install
修改config.h.in屏蔽#undef malloc 和 #undef realloc后执行,
这样json就已经安装成功。 - -std=c99 -I/PATH/incldue/json -L/PATH/lib -ljson
在程序中使用json的api只需要在编译程序时添加以上信息
例如这样编译库中test1.c:
gcc test1.c -o test1 -std=c99 -I/PATH/incldue/json -L/PATH/lib -ljson
2. 数据结构(data structures)
比较重要的数据结构:
1. struct json_object
struct json_object
{
enum json_type o_type; //json对象类型
json_object_delete_fn *_delete; //free json对象
json_object_to_json_string_fn *_to_json_string; //转换json对象为json格式的字符串
int _ref_count; //json对象引用计数,初始化为1
struct printbuf *_pb; //存储json对象转换后的字符串内存区域地址
union data {
boolean c_boolean; //boolean类型json对象的数值
double c_double; //double类型json对象的数值
int c_int; //int类型json对象的数值
struct lh_table *c_object; //存储object类型json对象的hash_table地址
struct array_list *c_array; //存储array类型json对象的字符串数组地址
char *c_string; //存储string类型json对象的地址
} o;
};
2. struct json_tokener
struct json_tokener
{
char *str;
struct printbuf *pb; //用于分类存储待解析字符串的buffer
int depth; //结构体成员stack的depth
int is_double; //value是double or int
int st_pos; //string中某字符的position,string包括:null,true,false,unicode
int char_offset; //某字符在待解析字符串中的offset
ptrdiff_t err; //字符串解析出错代码
unsigned int ucs_char; //unicode的值
char quote_char; //存储引号"
struct json_tokener_srec stack[JSON_TOKENER_MAX_DEPTH]; //存储待解析字符串中所有的json对象
};
3. struct json_object 和 struct json_tokener 的成员struct printbuf定义如下,定义一个buffer,用于存储字符串;
struct printbuf {
char *buf;
int bpos; //buf中已经使用的数量
int size; //buf的size
};
4. struct json_tokener 的成员struct json_tokener_srec定义如下,定义一个stack,用于存储不同类型object对象;
struct json_tokener_srec
{
enum json_tokener_state state, saved_state;
struct json_object *obj; //暂未使用
struct json_object *current;
char *obj_field_name; //object某一个field的name
};
3. 文件(files)
获取json-c-0.9.tar.gz解压后,包含的源码文件如图,下面内容大致介绍文件的主要代码:
json_object.c
定义json对象的操作函数,包括新建、删除、转换、添加等函数;1. json_object_new()/json_object_to_json_string()/json_object_generic_delete() 三个函数分别new一个json对象/转换json对象为json格式的字符串/删除json对象,相当于父类。
json_object_new()实现:
static struct json_object* json_object_new(enum json_type o_type)
{
struct json_object *jso;
jso = (struct json_object*)calloc(sizeof(struct json_object), 1); //new一个json_object对象,并赋值
if(!jso) return NULL;
jso->o_type = o_type;
jso->_ref_count = 1;
jso->_delete = &json_object_generic_delete;
...
return jso;
}
json_object_to_json_string()实现
const char* json_object_to_json_string(struct json_object *jso)
{
if(!jso) return "null";
if(!jso->_pb) {
if(!(jso->_pb = printbuf_new())) return NULL;
} else {
printbuf_reset(jso->_pb);//如果存在,则复位存储json对象转换后的字符串的内存区域,否则new一个新区域
}
if(jso->_to_json_string(jso, jso->_pb) < 0) return NULL; //依据传入的json对象(struct json_object *jso),
//jso->_to_json_string(jso, jso->_pb)调用相应的json_object_**_to_json_string()函数
return jso->_pb->buf;
}
json_object_generic_delete()实现
static void json_object_generic_delete(struct json_object* jso)
{
...
printbuf_free(jso->_pb);
free(jso);
}
2. json_object_new_**()/json_object_**_to_json_string()/json_object_**_delete()
三个系列函数分别new一个“子类”的json对象/转换“子类”的json对象为json格式的字符串/删除“子类”的json对象;
其中的“子类”的json对象包括boolean、double、int、object、array、string等类型;
以object类型json对象为例:
json_object_new_**()实现
struct json_object* json_object_new_object(void)
{
struct json_object *jso = json_object_new(json_type_object);
if(!jso) return NULL;
jso->_delete = &json_object_object_delete; //在json_object_new()基础上填充._to_json_string、.o.c_object方法,
jso->_to_json_string = &json_object_object_to_json_string; //并覆写._delete方法
jso->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES,
NULL, &json_object_lh_entry_free);
return jso;
}
json_object_**_to_json_string()实现
static int json_object_object_to_json_string(struct json_object* jso,
struct printbuf *pb)
{
int i=0;
struct json_object_iter iter;
sprintbuf(pb, "{"); //object类型json对象的json格式字符串开始
/* CAW: scope operator to make ANSI correctness */
/* CAW: switched to json_object_object_foreachC which uses an iterator struct */
json_object_object_foreachC(jso, iter) { //遍历json对象所有的key和value
if(i) sprintbuf(pb, ",");
sprintbuf(pb, " \"");
json_escape_str(pb, iter.key);
sprintbuf(pb, "\": ");
if(iter.val == NULL) sprintbuf(pb, "null");
else iter.val->_to_json_string(iter.val, pb); //依据json对象(iter.val),选择相应的json_object_**_to_json_string()
i++;
}
return sprintbuf(pb, " }"); //object类型json对象的json格式字符串结束
}
json_object_**_delete()实现
static void json_object_object_delete(struct json_object* jso)
{
lh_table_free(jso->o.c_object); //free hash_table
json_object_generic_delete(jso); //free json对象
}
3. json_object_get()/json_object_put()
增加json对象引用计数/减少json对象引用计数
4. json_object_object_add()/json_object_object_get()/json_object_object_del()
添加一个feild到object类型的json对象/从object类型的json对象获取一个feild/删除object类型的json对象中一个feild
5. json_object_array_add()/json_object_array_put_idx()/json_object_array_get_idx()
添加一个element(json对象)到array类型的json对象尾部/添加一个element到array类型的json对象的
某个位置/获取array类型的json对象的某个位置的element
- json_tokener.c
定义解析字符串为json对象函数以及两个重要的宏POP_CHAR(dest, tok)和ADVANCE_CHAR(str, tok)
POP_CHAR(dest, tok)
#define POP_CHAR(dest, tok) \
(((tok)->char_offset == len) ? \
(((tok)->depth == 0 && state == json_tokener_state_eatws && saved_state == json_tokener_state_finish) ? \
(((tok)->err = json_tokener_success), 0) \
: \
(((tok)->err = json_tokener_continue), 0) \
) : \
(((dest) = *str), 1) \
) //将字符*str赋值给dest,并返回1;当到达字符串结尾(tok->char_offset == len)时检查depth、state和saved_state,设置tok->err,并返回0
ADVANCE_CHAR(str, tok)
#define ADVANCE_CHAR(str, tok) \
( ++(str), ((tok)->char_offset)++, c) //遍历字符串str,同步递增tok->char_offset,并返回字符c
//和POP_CHAR(c, tok)一起使用,实现对字符串str的字符进行遍历,并设置遍历的结果状态(tok->err)
定义的函数包括新建/删除json_tokener对象函数json_tokener_new()/json_tokener_free(),以及解析函数json_tokener_parse**();
其中json_tokener_parse_ex()函数很重要,此函数通过state和saved_state两个状态控制函数流程,state和saved_state 取下面枚举值;
enum json_tokener_state {
json_tokener_state_eatws, //ew
json_tokener_state_start, //st
json_tokener_state_finish, //fi
...
json_tokener_state_string, //str
json_tokener_state_string_escape, //str_esc
json_tokener_state_escape_unicode, //uni
...
json_tokener_state_array, //arr
json_tokener_state_array_add, //arr_a
json_tokener_state_array_sep, //arr_s
json_tokener_state_object_field_start, //ofs
json_tokener_state_object_field, //of
json_tokener_state_object_field_end, //ofe
json_tokener_state_object_value, //ov
json_tokener_state_object_value_add, //ova
json_tokener_state_object_sep //os
};
json_tokener_parse_ex() 函数可以解析boolean、double、int、object、array、string等类型的json对象,以object类型的json对象的
解析过程为例,说明解析流程(重点介绍解析过程中state和saved_state 转换过程,详细流程查看源码)
linkhash.c
这个文件中函数用于处理存储object类型json对象的hash_table,包括新建hash_table函数lh_table_new()/lh_**_table_new(),删除hash_table
函数lh_table_free(),添加record到hash_table函数lh_table_insert(),删除record函数lh_table_delete()/lh_table_delete_entry(),查找record
函数lh_table_lookup()/lh_table_lookup_entry();
关于hash_table的知识请参考预备知识 : linux内核哈希表hlist;arraylist.c
这个文件中函数用于处理存储array类型json对象的arraylist,包括新建arraylist函数array_list_new(),删除arraylist函数array_list_free(),
添加元素到arraylist函数array_list_add()/array_list_put_idx(),查找元素函数array_list_get_idx();debug.c
定义不等等级的日志输出函数以及对应的宏,MC_DEBUG()/mc_debug()/..;printbuf.c
定义内存操作函数,新建函数printbuf_new(),内存拷贝函数printbuf_memappend()等;json_util.c
定义从文件读取字符串解析为json对象函数json_object_from_file()和将json对象转化为json格式字符串写入文件函数json_object_to_file();
4. json格式通信的收发流程
- 接收:
read()(读取字符串数据)
–> json_tokener_parse()(从字符串数据中解析json对象)
–> json_object_get_*()(从json对象中获取数据value,如int、double、string、array、object等) - 发送:
json_object_new_*()(生成json对象)
–> json_object_object_add()/json_object_array_add()/json_object_to_json_string().. (往json对象添加数据并转换字符串数据)
–> write()(发送字符串数据)
5. 举例
项目中使用json格式字符串进行进程间通信,流程如下:
读取进程间通信数据(字符串) –> 解析出json对象 –> 处理json对象 –> … –> 生成json对象并添加数据 –> 转换json对象为json格式字符串并发送
6. 小结
本文简绍项目中使用的json-c-0.9库解析、处理json格式字符串的实现流程,并简单说明使用json-c-0.9进行通信的原理,欢迎指正和讨论^_^。
疑问
- json_object.h 30~38行的定义有什么用?
printbuf、lh_table、… 这些结构体在别的地方已经定义,再次定义的作用是什么..
/* forward structure definitions */
typedef int boolean;
typedef struct printbuf printbuf;
typedef struct lh_table lh_table;
typedef struct array_list array_list;
typedef struct json_object json_object;
typedef struct json_object_iter json_object_iter;
typedef struct json_tokener json_tokener;