MsgPack简介

3 分钟阅读

MsgPack 是一个序列化库,可以将对象序列化为二进制数据,也可以将二进制数据反序列化为对象。

与其他数据序列化格式(如JSON和XML)相比,MsgPack 具有更高的性能和更小的序列化大小。它的序列化和反序列化过程非常快速,并且生成的二进制数据体积小,节省带宽和存储空间。

MsgPack 提供了多种语言的实现,包括但不限于 C/C++、Java、Python、JavaScript、Ruby、Go、C#、PHP 等,使得不同语言的应用程序可以方便地进行数据交换和通信。

MsgPack 的官方网站:https://msgpack.org/

MsgPack C++ 版本开源代码库

官网简单示例

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

int main(void) {
        // serializes this object.
        std::vector<std::string> vec;
        vec.push_back("Hello");
        vec.push_back("MessagePack");

        // serialize it into simple buffer.
        msgpack::sbuffer sbuf;
        msgpack::pack(sbuf, vec);

        // deserialize it.
        msgpack::object_handle oh =
            msgpack::unpack(sbuf.data(), sbuf.size());

        // print the deserialized object.
        msgpack::object obj = oh.get();
        std::cout << obj << std::endl;  //=> ["Hello", "MessagePack"]

        // convert it into statically typed object.
        std::vector<std::string> rvec;
        obj.convert(rvec);
}

编译并输出:

$ g++ -Ipath_to_msgpack/include hello.cc -o hello
$ ./hello
["Hello", "MessagePack"]

流式序列化

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

int main() {
        // serializes multiple objects using msgpack::packer.
        msgpack::sbuffer buffer;

        msgpack::packer<msgpack::sbuffer> pk(&buffer);
        pk.pack(std::string("Log message ... 1"));
        pk.pack(std::string("Log message ... 2"));
        pk.pack(std::string("Log message ... 3"));

        // deserializes these objects using msgpack::unpacker.
        msgpack::unpacker pac;

        // feeds the buffer.
        pac.reserve_buffer(buffer.size());
        memcpy(pac.buffer(), buffer.data(), buffer.size());
        pac.buffer_consumed(buffer.size());

        // now starts streaming deserialization.
        msgpack::object_handle oh;
        while(pac.next(oh)) {
            std::cout << oh.get() << std::endl;
        }

        // results:
        // $ g++ -Ipath_to_msgpack/include stream.cc -o stream
        // $ ./stream
        // "Log message ... 1"
        // "Log message ... 2"
        // "Log message ... 3"
}

序列化 arraymap

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

int main() {
        // serializes multiple objects into one message containing an array using msgpack::packer.
        msgpack::sbuffer buffer;

        msgpack::packer<msgpack::sbuffer> pk(&buffer);
        pk.pack_array(3);
        pk.pack(std::string("Log message ... 1"));
        pk.pack(std::string("Log message ... 2"));
        pk.pack(std::string("Log message ... 3"));

        // serializes multiple objects into one message containing a map using msgpack::packer.
        msgpack::sbuffer buffer2;

        msgpack::packer<msgpack::sbuffer> pk2(&buffer2);
        pk2.pack_map(2);
        pk2.pack(std::string("x"));
        pk2.pack(3);
        pk2.pack(std::string("y"));
        pk2.pack(3.4321);

}

序列化自定义类型

#include <msgpack.hpp>
#include <vector>
#include <string>

class myclass {
private:
    std::string m_str;
    std::vector<int> m_vec;
public:
    MSGPACK_DEFINE(m_str, m_vec);
};

int main() {
        std::vector<myclass> vec;
        // add some elements into vec...

        // you can serialize myclass directly
        msgpack::sbuffer sbuf;
        msgpack::pack(sbuf, vec);

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

        msgpack::object obj = oh.get();

        // you can convert object to myclass directly
        std::vector<myclass> rvec;
        obj.convert(rvec);
}

封装序列化函数

继承的方式

#include <msgpack.hpp>
#include <vector>
#include <iostream>
#include <string>
#include <random>

/// 获取随机整数
int GetRandomInt(int min = 0, int max = 1000000)
{
    static std::random_device rd;
    static std::mt19937 gen(rd());
    static std::uniform_int_distribution<> dis(min, max);
    return dis(gen);
}

/// 获取随机字符串
std::string GetRandomString(size_t len = 10)
{
    static std::random_device rd;
    static std::mt19937 gen(rd());
    static std::uniform_int_distribution<> dis(0, 25);

    std::string str;
    for (int i = 0; i < len; ++i)
    {
        str.push_back('a' + dis(gen));
    }

    return str;
}

/// 序列化函数基类
template <typename T>
class MsgPackSerialization
{
 public:
    virtual ~MsgPackSerialization() = default;
    bool operator==(const MsgPackSerialization&) const = default;

    /// 序列化
    std::vector<char> Serialization()
    {
        msgpack::sbuffer sbuf;
        msgpack::pack(sbuf, *(static_cast<T*>(this)));
        std::vector<char> vec(sbuf.data(), sbuf.data() + sbuf.size());
        return vec;
    }

    /// 反序列化
    void Deserialization(const std::vector<char>& vec)
    {
        msgpack::object_handle oh = msgpack::unpack(vec.data(), vec.size());
        msgpack::object obj = oh.get();
        obj.convert(*(static_cast<T*>(this)));
    }
};

/// 集成序列化类
class myclass : public MsgPackSerialization<myclass>
{
 public:
    bool operator==(const myclass&) const = default;
    myclass& operator=(const myclass& rhs)
    {
        if (this != &rhs)
        {
            m_str = rhs.m_str;
            m_vec = rhs.m_vec;
        }
        return *this;
    }

    /// 获取随机对象
    static myclass GetRandomObj()
    {
        myclass obj;
        obj.m_str = GetRandomString(10);
        auto num = GetRandomInt(0, 10);
        for (int i = 0; i < num; ++i)
        {
            obj.m_vec.push_back(GetRandomInt(0, 1000));
        }

        return obj;
    }

public:
    /// 为 msgpack 定义序列化和反序列化的字段
    MSGPACK_DEFINE(m_str, m_vec);

private:
    std::string m_str;
    std::vector<int> m_vec;
};

int main()
{
    /// 获取随机对象
    auto obj = myclass::GetRandomObj();
    decltype(obj) obj2;
    /// 序列化
    auto vec = obj.Serialization();
    /// 反序列化
    obj2.Deserialization(vec);

    if (obj2 == obj)
    {
        std::cout << "obj2 == obj" << std::endl;
    }
    else
    {
        std::cout << "obj2 != obj" << std::endl;
    }

    return 0;
}

使用更加复杂的类进行序列化

class myclass2 : public MsgPackSerialization<myclass2>
{
 public:
    bool operator==(const myclass2&) const
    {
        return m_str == m_str && m_vec == m_vec
            && m_class == m_class && m_vec_class == m_vec_class;
    }

    /// 获取本类的随机对象
    static myclass2 GetRandomObj()
    {
        myclass2 obj;
        obj.m_str = GetRandomString(10);
        auto num = GetRandomInt(0, 10);

        for (int i = 0; i < num; ++i)
        {
            obj.m_vec.push_back(GetRandomInt(0, 1000));
            obj.m_vec_class.push_back(myclass::GetRandomObj());
        }

        obj.m_class = myclass::GetRandomObj();

        return obj;
    }

public:
    /// 为 msgpack 定义序列化和反序列化的字段
    MSGPACK_DEFINE(m_str, m_vec, m_class, m_vec_class);

private:
    std::string m_str;
    std::vector<int> m_vec;
    myclass m_class;
    std::vector<myclass> m_vec_class;
};

int main()
{
    /// 获取随机对象
    auto obj = myclass2::GetRandomObj();
    decltype(obj) obj2;
    /// 序列化
    auto vec = obj.Serialization();
    /// 反序列化
    obj2.Deserialization(vec);

    if (obj2 == obj)
    {
        std::cout << "obj2 == obj" << std::endl;
    }
    else
    {
        std::cout << "obj2 != obj" << std::endl;
    }

    return 0;
}

组合的方式

MSGPACK_DEFINE 宏定义的下面添加如下两个函数,即可拥有序列化和反序列化的功能。

#define MSGPACK_DEFINE(...) ...\
    std::shared_ptr<std::vector<char>> Serialization()                                      \
    {                                                                                       \
        msgpack::sbuffer sbuf;                                                              \
        msgpack::pack(sbuf, *this);                                                         \
        return std::make_shared<std::vector<char>>(sbuf.data(), sbuf.data() + sbuf.size()); \
    }                                                                                       \
    void Deserialization(const std::shared_ptr<std::vector<char>>& vec)                     \
    {                                                                                       \
        msgpack::object_handle oh = msgpack::unpack(vec->data(), vec->size());               \
        msgpack::object obj = oh.get();                                                     \
        obj.convert(*this);                                                                  \
    }

更新时间: