c语言序列化和反序列化
程序员文章站
2022-06-16 08:38:44
...
c语言序列化和反序列化
c语言序列化和反序列化
网络调用,数据存取,数据传输都需要把数据序列化和反序列化。杀鸡不喜欢用牛刀,自己从底层设计协议又太繁琐,难以维护和扩展。使用 tpl (http://troydhanson.github.io/tpl/)这个库,可以很方便地构造自己的协议。
我采用 TLV 协议形式,即 (key,type,length,value) 4元组。key 是唯一的名称,type 是key保存的值的类型(用一个字符表示),length 是 value 的长度(应该叫 size 更贴近),value 是可以保存任何数据。发送数据的一方发送【“name”=“cheungmine”, “country”=“china”】, 接收数据的一方接收到之后,成为一个数组(UTArray),可以转为map(kvpairs_to_map),这样就容易获取特定些字段的内容了。
本文不特定于用户的具体协议内容,也不考虑数据存放的字节次序。这些都由用户自己完成。
因此可以定义个 tlv 数据节如下:
typedef struct kvpair_t
{
char *key; /* we'll use this field as the key */
char type;
union {
struct {
void *val;
uint32_t siz;
};
tpl_bin bval;
};
UT_hash_handle hh; /* makes this structure hashable */
} kvpair_t;
一个数据祯由1~N个这样的TLV 构成。我实现了基本的序列化(pack)和反序列化(unpack)基础功能。任何协议只要在这基础封装自己特有的字段(key)即可。下面是 tplut.h和tplut.c以及测试代码。
下面的代码可以在任何平台编译使用。
tplut.h
/***********************************************************************
* Copyright (c) 2008-2080 pepstack.com, [email protected]
*
* ALL RIGHTS RESERVED.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
***********************************************************************/
/**
* @file: tplut.h
* tpl protocol utility
*
* @author: [email protected]
*
* @version: 1.0.0
* @create: 2019-05-02
* @update: 2019-05-03
*/
#ifndef TPLUT_H_INCLUDED
#define TPLUT_H_INCLUDED
#if defined(__cplusplus)
extern "C"
{
#endif
#include <stdio.h>
#include <stdlib.h>
#include <uthash/utarray.h>
#include <uthash/uthash.h>
/* http://troydhanson.github.io/tpl/userguide.html */
#include <tpl/tpl.h>
#define TPLUT_SUCCESS 0
#define TPLUT_ERROR (-1)
typedef struct kvpair_t * kvmap_t;
/**
* S(sc)B
*
* A(S(sc)B)
*/
typedef struct kvpair_t
{
char *key; /* we'll use this field as the key */
char type;
union {
struct {
void *val;
uint32_t siz;
};
tpl_bin bval;
};
UT_hash_handle hh; /* makes this structure hashable */
} kvpair_t;
/**
* kvpair_t and tpl api
*/
extern UT_array * kvpairs_new (int capacity);
extern void kvpairs_free (UT_array *pairs);
extern void kvpairs_add (UT_array *pairs, char *key, char type, void *value, uint32_t size);
extern void kvpairs_print (UT_array *pairs);
extern tpl_node * kvpairs_pack (UT_array *pairs);
extern int dump_bin (tpl_node *tn, tpl_bin *outbin);
extern tpl_node * load_bin (tpl_bin *inbin);
extern UT_array * kvpairs_unpack (tpl_bin *tbin, int capacity);
/**
* kvmap_t api
*/
extern void kvmap_init (kvmap_t *map);
extern void kvmap_uninit (kvmap_t *map);
extern void kvpairs_to_map (UT_array *pairs, kvmap_t *map);
extern void kvmap_add (kvmap_t * map, kvpair_t * kv);
extern kvpair_t * kvmap_find (kvmap_t * map, const char * key);
extern void kvmap_delete (kvmap_t * map, kvpair_t *kv);
extern void kvmap_clear (kvmap_t * map);
#if defined(__cplusplus)
}
#endif
#endif /* TPLUT_H_INCLUDED */
tplut.c
/***********************************************************************
* Copyright (c) 2008-2080 pepstack.com, [email protected]
*
* ALL RIGHTS RESERVED.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
***********************************************************************/
/**
* @file: tplut.c
* tpl protocol utility
*
* @author: [email protected]
*
* @version: 1.0.0
* @create: 2019-05-02
* @update: 2019-05-03
*/
#include "tplut.h"
/**
* http://troydhanson.github.io/tpl/userguide.html
*
* Type Description Required argument type
* -----------------------------------------------------------------
* j 16-bit signed int int16_t* or equivalent
* v 16-bit unsigned int uint16_t* or equivalent
* i 32-bit signed int int32_t* or equivalent
* u 32-bit unsigned int uint32_t* or equivalent
* I 64-bit signed int int64_t* or equivalent
* U 64-bit unsigned int uint64_t* or equivalent
* c character (byte) char*
* s string char**
* f 64-bit double precision double* (varies by platform)
* B binary buffer (arbitrary-length)
*/
#include <pthread.h>
static void kvpair_copy(void *_dst, const void *_src)
{
kvpair_t *dst = (kvpair_t *)_dst, *src = (kvpair_t *)_src;
dst->key = (src->key ? strdup(src->key) : NULL);
dst->type = src->type;
if (src->val) {
dst->val = malloc(src->siz);
if (! dst->val) {
oom();
}
dst->siz = src->siz;
memcpy(dst->val, src->val, src->siz);
} else {
dst->val = NULL;
dst->siz = 0;
}
}
static void kvpair_dtor(void *_elt)
{
kvpair_t *elt = (kvpair_t *)_elt;
if (elt->key) {
free(elt->key);
}
if (elt->val) {
free(elt->val);
}
}
static const UT_icd ut_kvpair_icd UTARRAY_UNUSED = { sizeof(kvpair_t), NULL, kvpair_copy, kvpair_dtor };
/**
* kvpair_t and tpl api
*/
UT_array * kvpairs_new (int capacity)
{
UT_array *pairs;
utarray_new(pairs, &ut_kvpair_icd);
utarray_reserve(pairs, capacity);
return pairs;
}
void kvpairs_free (UT_array *pairs)
{
utarray_free(pairs);
}
void kvpairs_add (UT_array *pairs, char *key, char type, void *value, uint32_t size)
{
kvpair_t elt = { key, type, value, size };
utarray_push_back(pairs, &elt);
}
void kvpairs_print (UT_array *pairs)
{
kvpair_t *p = NULL;
while ((p = (kvpair_t *) utarray_next(pairs, p))) {
printf("%s = %.*s\n", p->key, (int) p->siz, (char *) p->val);
}
}
void kvpairs_to_map (UT_array *pairs, kvmap_t *map)
{
kvpair_t *p = NULL;
while ((p = (kvpair_t *) utarray_next(pairs, p))) {
kvmap_add(map, p);
}
}
tpl_node * kvpairs_pack (UT_array *pairs)
{
tpl_node *tn;
kvpair_t kv, *p;
tn = tpl_map("A(S(sc)B)", &kv, &kv.bval);
if (! tn) {
oom();
}
p = NULL;
while ((p = (kvpair_t *) utarray_next(pairs, p))) {
kv = *p;
tpl_pack(tn, 1);
}
return tn;
}
int dump_bin (tpl_node *tn, tpl_bin *tb)
{
if (tpl_dump(tn, TPL_GETSIZE, &tb->sz) == 0) {
tb->addr = malloc(tb->sz);
if (! tb->addr) {
oom();
}
if (tpl_dump(tn, TPL_MEM | TPL_PREALLOCD, tb->addr, tb->sz) == 0) {
return 0;
}
free(tb->addr);
}
return (-1);
}
tpl_node * load_bin (tpl_bin *tbin)
{
tpl_node *tn;
kvpair_t kv;
tn = tpl_map("A(S(sc)B)", &kv, &kv.bval);
if (! tn) {
oom();
}
if (tpl_load(tn, TPL_MEM /* | TPL_EXCESS_OK */, tbin->addr, tbin->sz) != 0) {
tpl_free(tn);
return NULL;
}
return tn;
}
UT_array * kvpairs_unpack (tpl_bin *tbin, int capacity)
{
UT_array *pairs;
tpl_node *tn;
kvpair_t kv;
pairs = kvpairs_new(capacity);
tn = tpl_map("A(S(sc)B)", &kv, &kv.bval);
if (! tn) {
kvpairs_free(pairs);
oom();
return NULL;
}
if (tpl_load(tn, TPL_MEM /* | TPL_EXCESS_OK */, tbin->addr, tbin->sz) != 0) {
tpl_free(tn);
kvpairs_free(pairs);
return NULL;
}
while (tpl_unpack(tn, 1) > 0) {
kvpairs_add(pairs, kv.key, kv.type, kv.val, kv.siz);
kvpair_dtor((void*) &kv);
}
tpl_free(tn);
return pairs;
}
/**
* kvmap_t api
*/
void kvmap_init (kvmap_t * map)
{
*map = NULL;
}
void kvmap_uninit (kvmap_t * map)
{
HASH_CLEAR(hh, *map);
*map = NULL;
}
void kvmap_add (kvmap_t * map, kvpair_t * kv)
{
HASH_ADD_STR(*map, key, kv);
}
kvpair_t * kvmap_find (kvmap_t * map, const char * key)
{
kvpair_t *kv = 0;
HASH_FIND_STR(*map, key, kv);
return kv;
}
void kvmap_delete (kvmap_t * map, kvpair_t *kv)
{
HASH_DEL(*map, kv);
}
void kvmap_clear (kvmap_t * map)
{
HASH_CLEAR(hh, *map);
}
测试代码
/**
* @file: test.c
* tpl transfer protocol test
*
* @author: [email protected]
*
* @version: 1.0.0
* @create: 2019-05-02
* @update: 2019-05-02
*/
#include "tplut.h"
void test_tplut (int id, int num)
{
int len;
char key[30];
char val[30];
UT_array * pairs;
tpl_bin tb;
int capacity = num;
pairs = kvpairs_new(capacity);
while (num-- > 0) {
snprintf(key, sizeof key, "(%d) key:%d", id, num);
len = snprintf(val, sizeof val, "(%d) val:%d", id, num);
kvpairs_add(pairs, key, 's', val, len + 1);
}
kvpairs_print(pairs);
printf("kvpairs_pack.\n");
tpl_node *tn = kvpairs_pack(pairs);
printf("kvpairs_free.\n");
kvpairs_free(pairs);
printf("dump_bin.\n");
if (dump_bin(tn, &tb) == 0) {
printf("dump_bin ok: sz=%u bytes.\n", tb.sz);
printf("load_bin\n");
tpl_node *tn2 = load_bin(&tb);
if (tn2) {
printf("load_bin ok.\n");
tpl_free(tn2);
}
UT_array * kvs = kvpairs_unpack(&tb, capacity);
if (kvs) {
printf("kvpairs_unpack out ok:\n");
kvpairs_print(kvs);
kvmap_t kvmap;
kvmap_init(&kvmap);
kvpairs_to_map(kvs, &kvmap);
kvmap_uninit(&kvmap);
kvpairs_free(kvs);
}
free(tb.addr);
}
printf("tpl_free.\n");
tpl_free(tn);
}
int main (int argc, char *argv[])
{
int i;
for (i = 0; i < 1000000; i++) {
test_tplut(i, 30);
}
printf("all is ok.\n");
return (0);
}
参考
上一篇: Mac下MySql的启动、停止