编程学习网 > 编程语言 > C/C++开发 > c语言序列化和反序列化
2022
11-16

c语言序列化和反序列化

今天编程学习网为大家讲解c语言序列化和反序列化,有需要的小伙伴可以参考一下:

网络调用,数据存取,数据传输都需要把数据序列化和反序列化。杀鸡不喜欢用牛刀,自己从底层设计协议又太繁琐,难以维护和扩展。使用 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, 350137278@qq.com
*
* 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: master@pepstack.com
 *
 * @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, 350137278@qq.com
*
* 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: master@pepstack.com
 *
 * @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: master@pepstack.com
 *
 * @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);
}
以上就是“c语言序列化和反序列化”的详细内容,想要了解更多C语言教程欢迎持续关注编程学习网

扫码二维码 获取免费视频学习资料

Python编程学习

查 看2022高级编程视频教程免费获取