您的位置:首页 > 理论基础 > 计算机网络

使用boost的archive做可变长度的网络消息数据打包

2009-12-16 21:47 531 查看
使用boost的archive做可变长度的网络消息数据打包

目的
在结构体上面可以定义std::string这样的数据,并方便打包与解包

核心
1. boost库提供了非常方便的对像序列化库boost::archive、boost::serialization,通过这两个库我们可以很方便的打包std里面像std::string、std::list这些类型的数据。
2. 打包数据我们当然要使用二进制的方式所以使用boost::archive::binary_iarchive、boost::archive::binary_oarchive。
3. 在真正编写代码的过程中发现这两个类为了序列化出来的数据有版本的区分还在输出的数据最前面加上一些版本信息,为了去除它们,最终我的解决方案是重写这两个类,将输出版本信息这块代码给关闭掉。
4. boost的序列化方法是在结构体上面做一个函数(全局的不提了),如下:
struct data
{
std::string v;
int v2;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & v;
ar & v2;
}
};
程序员总有一个通病“懒”,看到这样的代码就在想能不能将serialize函数给去掉或者让计算机自动生成,分析了很多,最后的解决方法是使用宏来处理在代码里可以看到MSG1、MSG2…MSG9这样的宏,它们就是为了完成这个想法而做的东西,很丑!!!(哪位有好的解决方法请一定要告知我,非常感谢)
5. 为了做到使用更加方便,简单做了MsgPack与MsgUnpack类来做打包与解包工作。

代码
//msg_binary_iarchive.h
#pragma once
// 这文件内容是直接复制的boost的binary_iarchive.hpp的内容做了点儿修改

#include <istream>

#pragma warning(push)
#pragma warning(disable : 4267)
#pragma warning(disable : 4996)
#include <boost/archive/binary_iarchive_impl.hpp>
#include <boost/archive/impl/basic_binary_iprimitive.ipp>
#include <boost/archive/impl/basic_binary_iarchive.ipp>
#pragma warning(pop)

namespace boost {
namespace archive {

class naked_binary_iarchive :
public binary_iarchive_impl<
boost::archive::naked_binary_iarchive,
std::istream::char_type,
std::istream::traits_type
>
{
public:
naked_binary_iarchive(std::istream & is, unsigned int flags = 0) :
binary_iarchive_impl<
naked_binary_iarchive, std::istream::char_type, std::istream::traits_type
>(is, flags)
{}
naked_binary_iarchive(std::streambuf & bsb, unsigned int flags = 0) :
binary_iarchive_impl<
naked_binary_iarchive, std::istream::char_type, std::istream::traits_type
>(bsb, flags)
{}
};

} // namespace archive
} // namespace boost

#include <boost/archive/shared_ptr_helper.hpp>

namespace boost {
namespace archive {

class msg_binary_iarchive :
public binary_iarchive_impl<
boost::archive::msg_binary_iarchive,
std::istream::char_type,
std::istream::traits_type
>,
public detail::shared_ptr_helper
{
public:
typedef binary_iarchive_impl<
boost::archive::msg_binary_iarchive,
std::istream::char_type,
std::istream::traits_type
> base;
msg_binary_iarchive(std::istream & is, unsigned int flags = 0) :
binary_iarchive_impl<
msg_binary_iarchive, std::istream::char_type, std::istream::traits_type
>(is, flags)
{}
msg_binary_iarchive(std::streambuf & bsb, unsigned int flags = 0) :
binary_iarchive_impl<
msg_binary_iarchive, std::istream::char_type, std::istream::traits_type
>(bsb, flags)
{}

template<class T>
void load_override(T & t, BOOST_PFTO int)
{
BOOST_MPL_ASSERT_NOT(( boost::is_pointer<T> ));
base::load_override(t, 0);
}

// 这些信息都不要了
void load_override(boost::archive::class_id_optional_type &, int){}
void load_override(boost::archive::tracking_type & t, int){t.t = false;}
void load_override(boost::archive::version_type & t, int){t.t = 0;}
};

} // namespace archive
} // namespace boost

// required by export
BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::archive::msg_binary_iarchive)
BOOST_SERIALIZATION_USE_ARRAY_OPTIMIZATION(boost::archive::msg_binary_iarchive)

//msg_binary_oarchive.h
#pragma once
// 这文件内容是直接复制的boost的binary_oarchive.hpp的内容做了点儿修改

#include <ostream>

#pragma warning(push)
#pragma warning(disable : 4267)
#pragma warning(disable : 4996)
#include <boost/archive/binary_oarchive_impl.hpp>
#include <boost/archive/impl/basic_binary_oprimitive.ipp>
#include <boost/archive/impl/basic_binary_oarchive.ipp>
#pragma warning(pop)

namespace boost {
namespace archive {

class msg_binary_oarchive :
public binary_oarchive_impl<
msg_binary_oarchive, std::ostream::char_type, std::ostream::traits_type
>
{
public:
typedef binary_oarchive_impl<
msg_binary_oarchive, std::ostream::char_type, std::ostream::traits_type
> base;
msg_binary_oarchive(std::ostream & os, unsigned int flags = 0) :
binary_oarchive_impl<
msg_binary_oarchive, std::ostream::char_type, std::ostream::traits_type
>(os, flags)
{}
msg_binary_oarchive(std::streambuf & bsb, unsigned int flags = 0) :
binary_oarchive_impl<
msg_binary_oarchive, std::ostream::char_type, std::ostream::traits_type
>(bsb, flags)
{}

template<class T>
void save_override(T & t, BOOST_PFTO int)
{
BOOST_MPL_ASSERT_NOT(( boost::is_pointer<T> ));
base::save_override(t, 0);
}

// 这些信息都不要了
void save_override(const boost::archive::class_id_optional_type &, int){}
void save_override(const boost::archive::tracking_type &, int){}
void save_override(const boost::archive::version_type &, int){}

};

typedef msg_binary_oarchive naked_binary_oarchive;

} // namespace archive
} // namespace boost

// required by export
BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::archive::msg_binary_oarchive)
BOOST_SERIALIZATION_USE_ARRAY_OPTIMIZATION(boost::archive::msg_binary_oarchive)

//MsgBinaryArchive.h
#pragma once

#include <strstream>
#include "boost/serialization/string.hpp"
#include "boost/serialization/list.hpp"
#include "msg_binary_iarchive.h"
#include "msg_binary_oarchive.h"

#define MSG1(mn,t1,n1)/
struct mn/
{/
t1 vn1;/
template<class Archive> void serialize(Archive & ar, const unsigned int version)/
{/
ar & vn1;/
}/
};

#define MSG2(mn,t1,n1,t2,n2)/
struct mn/
{/
t1 n1;/
t2 n2;/
template<class Archive> void serialize(Archive & ar, const unsigned int version)/
{/
ar & n1;/
ar & n2;/
}/
};

#define MSG3(mn,t1,n1,t2,n2,t3,n3)/
struct mn/
{/
t1 n1;/
t2 n2;/
t3 n3;/
template<class Archive> void serialize(Archive & ar, const unsigned int version)/
{/
ar & n1;/
ar & n2;/
ar & n3;/
}/
};

#define MSG4(mn,t1,n1,t2,n2,t3,n3,t4,n4)/
struct mn/
{/
t1 n1;/
t2 n2;/
t3 n3;/
t4 n4;/
template<class Archive> void serialize(Archive & ar, const unsigned int version)/
{/
ar & n1;/
ar & n2;/
ar & n3;/
ar & n4;/
}/
};

#define MSG5(mn,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5)/
struct mn/
{/
t1 n1;/
t2 n2;/
t3 n3;/
t4 n4;/
t5 n5;/
template<class Archive> void serialize(Archive & ar, const unsigned int version)/
{/
ar & n1;/
ar & n2;/
ar & n3;/
ar & n4;/
ar & n5;/
}/
};

#define MSG6(mn,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6)/
struct mn/
{/
t1 n1;/
t2 n2;/
t3 n3;/
t4 n4;/
t5 n5;/
t6 n6;/
template<class Archive> void serialize(Archive & ar, const unsigned int version)/
{/
ar & n1;/
ar & n2;/
ar & n3;/
ar & n4;/
ar & n5;/
ar & n6;/
}/
};

#define MSG7(mn,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7)/
struct mn/
{/
t1 n1;/
t2 n2;/
t3 n3;/
t4 n4;/
t5 n5;/
t6 n6;/
t7 n7;/
template<class Archive> void serialize(Archive & ar, const unsigned int version)/
{/
ar & n1;/
ar & n2;/
ar & n3;/
ar & n4;/
ar & n5;/
ar & n6;/
ar & n7;/
}/
};

#define MSG8(mn,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7,t8,n8)/
struct mn/
{/
t1 n1;/
t2 n2;/
t3 n3;/
t4 n4;/
t5 n5;/
t6 n6;/
t7 n7;/
t8 n8;/
template<class Archive> void serialize(Archive & ar, const unsigned int version)/
{/
ar & n1;/
ar & n2;/
ar & n3;/
ar & n4;/
ar & n5;/
ar & n6;/
ar & n7;/
ar & n8;/
}/
};

#define MSG9(mn,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7,t8,n8,t9,n9)/
struct mn/
{/
t1 n1;/
t2 n2;/
t3 n3;/
t4 n4;/
t5 n5;/
t6 n6;/
t7 n7;/
t8 n8;/
t9 n9;/
template<class Archive> void serialize(Archive & ar, const unsigned int version)/
{/
ar & n1;/
ar & n2;/
ar & n3;/
ar & n4;/
ar & n5;/
ar & n6;/
ar & n7;/
ar & n8;/
ar & n9;/
}/
};

class MsgPack
{
public:
MsgPack():
_oa(_os, boost::archive::no_header)
{}

template <class T>
MsgPack& operator & (const T & v)
{
reset();
_oa & v;

return *this;
}

template <class T>
MsgPack& operator << (const T & v)
{
_oa & v;

return *this;
}

void reset()
{
_os.freeze(false);
_os.seekp(0);
_os.seekg(0);
}

const char* buffer()
{
return _os.str();
}

size_t size()
{
return _os.pcount();
}

private:
std::strstream							_os;
boost::archive::msg_binary_oarchive 	_oa;
};

class MsgUnpack
{
public:
MsgUnpack():
_ia(_is, boost::archive::no_header)
{}

void reset(const char* buf, size_t size)
{
if (_is.pcount())
{
_is.seekp(0);
_is.seekg(0);
}
_is.write(buf, (std::streamsize)size);
}

template <class T>
MsgUnpack& operator >> (T & v)
{
_ia & v;

return *this;
}

private:
std::strstream							_is;
boost::archive::msg_binary_iarchive 	_ia;
};

/* 例子
===============================================================================
// 定义一个有两个成员变量的消息结构
MSG2(stTestMsg,
float, x,
std::string, str);

// 定义一个有四个成员变量的消息结构
MSG4(A,
std::list<int>, _list,
int, _int,
std::string, _str,
char, _char);

void test()
{
std::string recvMsgBuf;

// 发送
{
MsgPack msgPack;

stTestMsg testmsg = {3.2f,"fdsfd"};
A a;
a._char = 'a';
a._int = 343;
a._list.push_back(3);
a._list.push_back(432);
a._str = "test str";

// 打包消息
msgPack & a;		// 重置消息缓冲,并打包数据
msgPack << testmsg;	// 在当前包后面添加数据

// 可以用这两个玩意儿去发送消息了
const char* msgBuf = msgPack.buffer();
size_t msgSize = msgPack.size();
recvMsgBuf.resize(msgSize);
memcpy((char*)recvMsgBuf.c_str(), msgBuf, msgSize);
}

// 接收
{
MsgUnpack msgUnpack;

stTestMsg testmsg;
A a;

// 设置接收到的包数据
msgUnpack.reset(recvMsgBuf.c_str(), recvMsgBuf.size());
// 解包数据到消息结构体内
msgUnpack >> a >> testmsg;
}
}
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐