Table of Contents
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
概括来讲就是:
- true、false 之类的:这些太简单了,直接给1个字节,(0xc3 表示true,0xc2表示false)
- 不用表示长度的:就是数字之类的,他们天然是定长的,是用一个字节表示后面的内容是什么,比如用(0xcc 表示这后面,是个uint 8,用oxcd表示后面是个uint 16,用 0xca 表示后面的是个float 32)。对于数字做了进一步的压缩处理,根据大小选择用更少的字节进行存储,比如一个长度<256的int,完全可以用一个字节表示。
- 不定长的:比如字符串、数组、二进制数据(bin类型),类型后面加 1~4个字节,用来存字符串的长度,如果是字符串长度是256以内的,只需要1个字节,MessagePack能存的最长的字符串,是(2^32 -1 ) 最长的4G的字符串大小。
- 高级结构:MAP结构,就是k-v 结构的数据,和数组差不多,加1~4个字节表示后面有多少个项
- 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/
- 启动cmake GUI客户端。
- 设置“源代码在哪里:”文本框和“在哪里构建二进制文件:”文本框。
- 点击“配置”按钮。
- 选择您的Visual Studio版本。
- 点击“生成”按钮。
- 在Visual Studio上打开创建的msgpack.sln。
- 全部构建。
文献资料
您可以在Wiki上获得包括教程在内的更多信息 。
贡献
msgpack-c
在GitHub上通过msgpack / msgpack-c开发。要报告问题或发送请求请求,请使用 问题跟踪器。
这是伟大的贡献者名单。
执照
msgpack-c
根据Boost软件许可1.0版获得许可。有关LICENSE_1_0.txt
详细信息,请参见文件。