如何使用msgpack-c正确解压缩和提取数据?

时间:2013-03-13 18:45:15

标签: c serialization deserialization msgpack

我目前正在尝试在用C编写的项目中使用msgpack。我正在使用msgpack来序列化结构的内容,然后通过网络发送,并反序列化为相应的结构在另一边。

我正在尝试做的简明版本:

#include <stdio.h>
#include <msgpack.h>
#include <stdbool.h>

typedef someStruct{
uint32_t a;
uint32_t b;
float    c;
} someStruct;

int main (void){
    someStruct data;
    /* ... Fill 'data' with some data for test purposes ...*/

    msgpack_sbuffer* buff = msgpack_sbuffer_new();
    msgpack_packer* pck = msgpack_packer_new(buff, msgpack_sbuffer_write);        

    someStruct* structs = malloc(sizeof(someStruct) * 10);

    /* ... Fill 'structs' with members containing test data ... */
    // Serialize
    msgpack_pack_array (pck, 10);

    int i;
    for(i = 0 ; i < 10 ; i++){
    msgpack_pack_array (pck, 3);
    msgpack_pack_uint32 (pck, structs[i].a);
    msgpack_pack_uint32 (pck, structs[i].b);
    msgpack_pack_float (pck, structs[i].c);
    }

    free(structs);
    msgpack_packer_free(pck);

    // Deserialize
    msgpack_unpacked msg;
    msgpack_unpacked_init(&msg);
    bool deserialize_success = msgpack_unpack_next
                               (&msg, buff->data, buff->size, NULL);
    if(!deserialize_success) /* Error */

    msgpack_object obj = msg.data;
    msgpack_object_print(stdout,obj); // This seems to work perfectly, indicating serialize / deserialize works as intended...

    someStruct deserialized_data;
    /* Insert code to extract and cast deserialized data to 'deserialized_data */
    // Clean
    msgpack_sbuffer_free(buff);
    msgpack_packer_free(pck);

return 0;
}

列出的代码或多或少地直接来自here,这似乎是msgpack-c上极少数资源之一。

有人能指出我在正确的方向上“重新创建”电线另一侧的原始结构吗?我发现实际使用反序列化数据的唯一方法是使用msgpack_object_print()调用从messagepack_object进行打印。但这似乎有效,所以我确定数据就在那里。

我是否需要以某种方式循环遍历序列化数据并使用带偏移的msgpack_unpack_next()来检索每个someStruct成员?将memcpy用于本地字节缓冲区?

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:6)

请在下面找到一个重写版本,说明如何打包/解压缩您的数据。

整个想法是以连续的方式打包结构的每个连续字段,并在解包时应用(当然)相同的逻辑。

在打包后,您可以随意使用缓冲区(例如通过网络发送,保存在磁盘上等)。

#include <stdio.h>
#include <assert.h>
#include <msgpack.h>

typedef struct some_struct {
  uint32_t a;
  uint32_t b;
  float c;
} some_struct;

static char *pack(const some_struct *s, int num, int *size);
static some_struct *unpack(const void *ptr, int size, int *num);

/* Fixtures */
some_struct ary[] = {
  { 1234, 5678, 3.14f },
  { 4321, 8765, 4.13f },
  { 2143, 6587, 1.34f }
};

int main(void) {
  /** PACK */
  int size;
  char *buf = pack(ary, sizeof(ary)/sizeof(ary[0]), &size);
  printf("pack %zd struct(s): %d byte(s)\n", sizeof(ary)/sizeof(ary[0]), size);

  /** UNPACK */
  int num;
  some_struct *s = unpack(buf, size, &num);
  printf("unpack: %d struct(s)\n", num);

  /** CHECK */
  assert(num == (int) sizeof(ary)/sizeof(ary[0]));
  for (int i = 0; i < num; i++) {
    assert(s[i].a == ary[i].a);
    assert(s[i].b == ary[i].b);
    assert(s[i].c == ary[i].c);
  }
  printf("check ok. Exiting...\n");

  free(buf);
  free(s);

  return 0;
}

static char *pack(const some_struct *s, int num, int *size) {
  assert(num > 0);
  char *buf = NULL;
  msgpack_sbuffer sbuf;
  msgpack_sbuffer_init(&sbuf);
  msgpack_packer pck;
  msgpack_packer_init(&pck, &sbuf, msgpack_sbuffer_write);
  /* The array will store `num` contiguous blocks made of a, b, c attributes */
  msgpack_pack_array(&pck, 3 * num);
  for (int i = 0; i < num; ++i) {
    msgpack_pack_uint32(&pck, s[i].a);
    msgpack_pack_uint32(&pck, s[i].b);
    msgpack_pack_float(&pck, s[i].c);
  }
  *size = sbuf.size;
  buf = malloc(sbuf.size);
  memcpy(buf, sbuf.data, sbuf.size);
  msgpack_sbuffer_destroy(&sbuf);
  return buf;
}

static some_struct *unpack(const void *ptr, int size, int *num) {
  some_struct *s = NULL;
  msgpack_unpacked msg;
  msgpack_unpacked_init(&msg);
  if (msgpack_unpack_next(&msg, ptr, size, NULL)) {
    msgpack_object root = msg.data;
    if (root.type == MSGPACK_OBJECT_ARRAY) {
      assert(root.via.array.size % 3 == 0);
      *num = root.via.array.size / 3;
      s = malloc(root.via.array.size*sizeof(*s));
      for (int i = 0, j = 0; i < root.via.array.size; i += 3, j++) {
        s[j].a = root.via.array.ptr[i].via.u64;
        s[j].b = root.via.array.ptr[i + 1].via.u64;
        s[j].c = root.via.array.ptr[i + 2].via.dec;
      }
    }
  }
  msgpack_unpacked_destroy(&msg);
  return s;
}