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

标签 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 用于本地字节缓冲区?

非常感谢任何帮助!

最佳答案

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

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

打包后,您可以按照自己的方式自由使用缓冲区(例如通过网络发送、保存在磁盘上等)。

#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;
}

关于c - 如何使用 msgpack-c 正确解包和提取数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15393838/

相关文章:

c# - DeflateStream 不适用于 MemoryStream?

c# - 使用restsharp反序列化 - 我尝试了文档,但它不起作用

C 程序没有正确读取参数

c - 这有什么意义 : *(void **)(&fptr) = dlsym(handle, "my_function");`

C# - 将私有(private)属性序列化为属性(数据协定)

perl - 我应该如何序列化一个 Moose 对象数组?

mongodb - MVC4 WebApi 序列化/反序列化 MongoDB ObjectId

java - 为什么serialVersionUID 对于可序列化类来说是 long 类型

c - 在带有 while 循环的 C 中使用递归函数的阶乘程序 c

c - 这个 setjmp/longjmp 上下文中的自动变量是什么?