MessagePack简介及使用:一种有效的二进制序列化格式

Table of Contents

什么是MessagePack

MessagePack的压缩原理

msgpack for C/C++


 

MessagePack是一种有效的二进制序列化格式。它使您可以在多种语言(如JSON)之间交换数据。但是它更快,更小。小整数被编码为一个字节,典型的短字符串除字符串本身外仅需要一个额外的字节。

什么是MessagePack

官方msgpack官网用一句话总结:
It’s like JSON.
but fast and small.
简单来讲,它的数据格式与json类似,但是在存储时对数字、多字节字符、数组等都做了很多优化,减少了无用的字符,二进制格式,也保证不用字符化带来额外的存储空间的增加。以下是官网给出的简单示例图:

图上这个json长度为27字节,但是为了表示这个数据结构,它用了9个字节(就是那些大括号、引号、冒号之类的,他们是白白多出来的)来表示那些额外添加的无意义数据。msgpack的优化在图上展示的也比较清楚了,省去了特殊符号,用特定编码对各种类型进行定义,比如上图的A7,其中前四个bit A就是表示str的编码,而且它表示这个str的长度只用半个字节就可以表示了,也就是后面的7,因此A7的意思就是表示后面是一个7字节长度的string。
有的同学就会问了,对于长度大于15(二进制1111)的string怎么表示呢?这就要看messagepack的压缩原理了。

 

MessagePack的压缩原理

核心压缩方式可参看官方说明messagepack specification
概括来讲就是:

  1. true、false 之类的:这些太简单了,直接给1个字节,(0xc3 表示true,0xc2表示false)
  2. 不用表示长度的:就是数字之类的,他们天然是定长的,是用一个字节表示后面的内容是什么,比如用(0xcc 表示这后面,是个uint 8,用oxcd表示后面是个uint 16,用 0xca 表示后面的是个float 32)。对于数字做了进一步的压缩处理,根据大小选择用更少的字节进行存储,比如一个长度<256的int,完全可以用一个字节表示。
  3. 不定长的:比如字符串、数组、二进制数据(bin类型),类型后面加 1~4个字节,用来存字符串的长度,如果是字符串长度是256以内的,只需要1个字节,MessagePack能存的最长的字符串,是(2^32 -1 ) 最长的4G的字符串大小。
  4. 高级结构:MAP结构,就是k-v 结构的数据,和数组差不多,加1~4个字节表示后面有多少个项
  5. Ext结构:表示特定的小单元数据。也就是用户自定义数据结构。

我们看一下官方给出的stringformat示意图

 

对于上面的问题,一个长度大于15(也就是长度无法用4bit表示)的string是这么表示的:用指定字节0xD9表示后面的内容是一个长度用8bit表示的string,比如一个160个字符长度的字符串,它的头信息就可以表示为D9A0。
这里值得一提的是Ext扩展格式,正是这种结构才保证了messagepack的完备性,因为实际的数据接口中自定义结构是非常常见的,简单的已知数据类型和高级结构map、array等并不能满足需求,因此需要一个扩展格式来与之配合。比如一个下面的接口格式:

{
  "error_no":0,
  "message":"",
  "result":{
    "data":[
      {
        "datatype":1,
        "itemdata":
            {//共有字段45个
              "sname":"\u5fae\u533b",
              "packageid":"330611",
              …
              "tabs":[
                        {
                          "type":1,
                          "f":"abc"
                        },
                        …
              ]
            }
      },
      …
    ],
    "hasNextPage":true,
    "dirtag":"soft"
  }
}

怎么把tabs中的子数据作为一个整体写入itemdata这个结构中呢?itemdata又怎么写入它的上层数据结构data中?这时Ext出马了。我们可以自定义一种数据类型,指定它的Type值,当解析遇到这个type时就按我们自定义的结构去解析。具体怎么实现后面我们在代码示例的时候会讲到。

 

msgpack for C/C++

https://msgpack.org/#languages


它就像JSON,但更小,更快。

总览

MessagePack是一种有效的二进制序列化格式,它使您可以在JSON之类的多种语言之间交换数据,但它更快,更小。小整数被编码为一个字节,短字符串除字符串本身外仅需要一个额外的字节。

在C中:

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

int main(void)
{
    /* msgpack::sbuffer is a simple buffer implementation. */
    msgpack_sbuffer sbuf;
    msgpack_sbuffer_init(&sbuf);

    /* serialize values into the buffer using msgpack_sbuffer_write callback function. */
    msgpack_packer pk;
    msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write);

    msgpack_pack_array(&pk, 3);
    msgpack_pack_int(&pk, 1);
    msgpack_pack_true(&pk);
    msgpack_pack_str(&pk, 7);
    msgpack_pack_str_body(&pk, "example", 7);

    /* deserialize the buffer into msgpack_object instance. */
    /* deserialized object is valid during the msgpack_zone instance alive. */
    msgpack_zone mempool;
    msgpack_zone_init(&mempool, 2048);

    msgpack_object deserialized;
    msgpack_unpack(sbuf.data, sbuf.size, NULL, &mempool, &deserialized);

    /* print the deserialized object. */
    msgpack_object_print(stdout, deserialized);
    puts("");

    msgpack_zone_destroy(&mempool);
    msgpack_sbuffer_destroy(&sbuf);

    return 0;
}

请参阅QUICKSTART-C.md以获取更多详细信息。

在C ++中:

#include <msgpack.hpp>
#include <string>
#include <iostream>
#include <sstream>

int main(void)
{
    msgpack::type::tuple<int, bool, std::string> src(1, true, "example");

    // serialize the object into the buffer.
    // any classes that implements write(const char*,size_t) can be a buffer.
    std::stringstream buffer;
    msgpack::pack(buffer, src);

    // send the buffer ...
    buffer.seekg(0);

    // deserialize the buffer into msgpack::object instance.
    std::string str(buffer.str());

    msgpack::object_handle oh =
        msgpack::unpack(str.data(), str.size());

    // deserialized object is valid during the msgpack::object_handle instance is alive.
    msgpack::object deserialized = oh.get();

    // msgpack::object supports ostream.
    std::cout << deserialized << std::endl;

    // convert msgpack::object instance into the original type.
    // if the type is mismatched, it throws msgpack::type_error exception.
    msgpack::type::tuple<int, bool, std::string> dst;
    deserialized.convert(dst);

    // or create the new instance
    msgpack::type::tuple<int, bool, std::string> dst2 =
        deserialized.as<msgpack::type::tuple<int, bool, std::string> >();

    return 0;
}

请参阅QUICKSTART-CPP.md以获取更多详细信息。

用法

C ++仅标头库

在C ++上使用msgpack时,只需将msgpack-c / include添加到包含路径中:

g++ -I msgpack-c/include your_source_file.cpp

如果要使用C版本的msgpack,则需要对其进行构建。您还可以安装msgpack的C和C ++版本。

建造和安装 从git仓库安装

使用终端(CLI)

你会需要:

  • gcc >= 4.1.0
  • cmake >= 2.8.0

C和C ++ 03:

$ git clone https://github.com/msgpack/msgpack-c.git
$ cd msgpack-c
$ cmake .
$ make
$ sudo make install

如果要改为设置C ++ 11或C ++ 17版本的msgpack,请执行以下命令:

$ git clone https://github.com/msgpack/msgpack-c.git
$ cd msgpack-c
$ cmake -DMSGPACK_CXX[11|17]=ON .
$ sudo make install

MSGPACK_CXX[11|17]标志不会影响安装文件。只是切换测试用例。所有文件都安装在所有设置中。

使用的C部分时msgpack-c,您需要构建和链接库。默认情况下,两个静态/共享库均已构建。如果只想构建静态库,请设置BUILD_SHARED_LIBS=OFF为cmake。如果只想构建共享库,则设置`BUILD_SHARED_L

Windows上的GUI

克隆msgpack -c git存储库。

$ git clone https://github.com/msgpack/msgpack-c.git

或使用GUI git客户端。

例如)乌龟git https://code.google.com/p/tortoisegit/

  1. 启动cmake GUI客户端
  2. 设置“源代码在哪里:”文本框和“在哪里构建二进制文件:”文本框。
  3. 点击“配置”按钮。
  4. 选择您的Visual Studio版本。
  5. 点击“生成”按钮。
  6. 在Visual Studio上打开创建的msgpack.sln。
  7. 全部构建。

文献资料

您可以在Wiki上获得包括教程在内的更多信息 。

贡献

msgpack-c在GitHub上通过msgpack / msgpack-c开发。要报告问题或发送请求请求,请使用 问题跟踪器

这是伟大的贡献者名单。

执照

msgpack-c根据Boost软件许可1.0版获得许可。有关LICENSE_1_0.txt详细信息,请参见文件。

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值