Как правильно распаковать и извлечь данные с помощью msgpack-c?

в настоящее время я пытаюсь использовать msgpack в проекте, написанном на C. я использую 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;
}

указанный код более или менее разорван прямо из здесь, который, кажется, является одним из очень немногих ресурсов на msgpack-c.

может ли кто-нибудь указать мне в правильном направлении, как "воссоздать" исходную структуру с другой стороны провода? Единственный способ использовать десериализованные данные-использовать вызов msgpack_object_print () для печати из messagepack_object. Это, однако, похоже, работает, поэтому я уверен, что данные есть.

Мне нужно как-то перебирать сериализованные данные и использовать msgpack_unpack_next () со смещением для извлечения каждого someStruct член? Использование memcpy для локального байтового буфера?

любая помощь очень ценится!

1 ответов


пожалуйста, найдите ниже переписанную версию, которая иллюстрирует, как упаковать / распаковать ваши данные.

вся идея состоит в том, чтобы упаковать каждое последующее поле вашей структуры, непрерывным образом, и применить (конечно) ту же логику во время распаковки.

сразу после обновления, вы можете использовать буфер, как вы хотите (например.г отправить по сети, сохранить на диске и т. д.).

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