如若描述或者代码当中有谬误之处,还望指正。

将数据能够在TCP中进行传输的两种方法
1.直接拷贝struct就可以了;
2.序列化。

拷贝Struct存在的问题
1.不能应付可变长类型的数据,比如STL中的那些容器,他们的长度都是不确定的。当然,STL的容器归根到底就是一个class;
2. 内存对齐的问题,Windows默认的对齐是4字节,如果不去刻意关闭掉对齐的话,那么可能会多出不少没必要的字节数,有时候,这个损耗是客观的。但是如 果关闭了,内存拷贝又会慢一些,内存IO相对于网络IO来说,速度是快的,略微的增加内存IO的压力来调优网络IO是可行的。

序列化是怎么序列化的?
其 实很简单,就是按位拷贝。在这里,我们使用一个uint8类型的变长数组作为一个容器。假设我们这里有一个uint16类型的数据,那么我们就把它拷贝进 去uint8的数组里面,那么它就占了两个元素,如果是uint32,则这个数据占了4个元素位。它的原理是非常的简单的。至于具体请参考下面代码里面的 ByteBuffer::append()方法。而那些class神马的,只要我们序列化的顺序和反序列化的顺序是配对的,我们就可以按照这个顺序进行序 列化和反序列化了。这个在BytBuffer里面已经默认支持了常用的几个STL容器(vector,list等)。

类型定义

#if defined(_MSC_VER)//// Windows/Visual C++//
    typedef signed __int8            int8;typedef unsigned __int8            uint8;typedef signed __int16            int16;typedef unsigned __int16        uint16;typedef signed __int32            int32;typedef unsigned __int32        uint32;typedef signed __int64            int64;typedef unsigned __int64        uint64;
#endif

有的类型的长度会因硬件或者操作系统而异,如果直接使用c++关键字中的类型定义可能会出现问题。因此,需要自己定义以上这样的类型。利用宏去适配各个操作系统或者硬件平台。

ByteBuffer的代码

//
/// 字节流缓冲类,可以进行序列化和解序列化操作,并且可以缓冲字节流数据。
//
class ByteBuffer
{
public:const static size_t DEFAULT_SIZE = 0x1000;ByteBuffer(): mReadPos(0), mWritePos(0){mStorage.reserve(DEFAULT_SIZE);}ByteBuffer(size_t res): mReadPos(0), mWritePos(0){mStorage.reserve(res);}ByteBuffer(const ByteBuffer &buf) : mReadPos(buf.mReadPos), mWritePos(buf.mWritePos), mStorage(buf.mStorage){}//
public:void clear(){mStorage.clear();mReadPos = mWritePos = 0;}template <typename T>void append(T value){append((uint8*)&value, sizeof(value));}template <typename T>void put(size_t pos, T value){put(pos, (uint8*)&value, sizeof(value));}//
public:ByteBuffer& operator<<(bool value){append<char>((char)value);return *this;}ByteBuffer& operator<<(uint8 value){append<uint8>(value);return *this;}ByteBuffer& operator<<(uint16 value){append<uint16>(value);return *this;}ByteBuffer& operator<<(uint32 value){append<uint32>(value);return *this;}ByteBuffer& operator<<(uint64 value){append<uint64>(value);return *this;}ByteBuffer& operator<<(int8 value){append<int8>(value);return *this;}ByteBuffer& operator<<(int16 value){append<int16>(value);return *this;}ByteBuffer& operator<<(int32 value){append<int32>(value);return *this;}ByteBuffer& operator<<(int64 value){append<int64>(value);return *this;}ByteBuffer& operator<<(float value){append<float>(value);return *this;}ByteBuffer& operator<<(double value){append<double>(value);return *this;}ByteBuffer& operator<<(time_t value){append<time_t>(value);return *this;}ByteBuffer& operator<<(const std::string& value){append((uint8 const *)value.c_str(), value.length());append((uint8)0);return *this;}ByteBuffer& operator<<(const char* str){append( (uint8 const *)str, str ? strlen(str) : 0);append((uint8)0);return *this;}//
public:ByteBuffer& operator>>(bool& value){value = read<char>() > 0 ? true : false;return *this;}ByteBuffer& operator>>(uint8& value){value = read<uint8>();return *this;}ByteBuffer& operator>>(uint16& value){value = read<uint16>();return *this;}ByteBuffer& operator>>(uint32& value){value = read<uint32>();return *this;}ByteBuffer& operator>>(uint64& value){value = read<uint64>();return *this;}ByteBuffer& operator>>(int8& value){value = read<int8>();return *this;}ByteBuffer& operator>>(int16& value){value = read<int16>();return *this;}ByteBuffer& operator>>(int32& value){value = read<int32>();return *this;}ByteBuffer& operator>>(int64& value){value = read<int64>();return *this;}ByteBuffer& operator>>(float &value){value = read<float>();return *this;}ByteBuffer& operator>>(double &value){value = read<double>();return *this;}ByteBuffer& operator>>(time_t& value){value = read<time_t>();return *this;}ByteBuffer& operator>>(std::string& value){value.clear();while (rpos() < size()){char c = read<char>();if (c == 0){break;}value += c;}return *this;}ByteBuffer& operator>>(char value[]){std::string strValue;strValue.clear();while (rpos() < size()){char c = read<char>();if (c == 0){break;}strValue += c;}strncpy(value, strValue.c_str(), strValue.size());return *this;}//
public:uint8 operator[](size_t pos){return read<uint8>(pos);}size_t rpos() const{return mReadPos;};size_t rpos(size_t rpos_){mReadPos = rpos_;return mReadPos;};size_t wpos() const{return mWritePos;}size_t wpos(size_t wpos_){mWritePos = wpos_;return mWritePos;}template <typename T> T read(){T r = read<T>(mReadPos);mReadPos += sizeof(T);return r;};template <typename T> T read(size_t pos) const{assert(pos + sizeof(T) <= size() || PrintPosError(false,pos,sizeof(T)));return *((T const*)&mStorage[pos]);}void read(uint8 *dest, size_t len){assert(mReadPos  + len  <= size() || PrintPosError(false, mReadPos,len));memcpy(dest, &mStorage[mReadPos], len);mReadPos += len;}const uint8* contents() const { return &mStorage[mReadPos]; }size_t size() const { return mStorage.size(); }bool empty() const { return mStorage.empty(); }void resize(size_t _NewSize){mStorage.resize(_NewSize);mReadPos = 0;mWritePos = size();};void reserve(size_t _Size){if (_Size > size()) mStorage.reserve(_Size);};void append(const std::string& str){append((uint8 const*)str.c_str(), str.size() + 1);}void append(const char *src, size_t cnt){return append((const uint8 *)src, cnt);}void append(const uint8 *src, size_t cnt){if (!cnt) return;assert(size() < 10000000);if (mStorage.size() < mWritePos + cnt){mStorage.resize(mWritePos + cnt);}memcpy(&mStorage[mWritePos], src, cnt);mWritePos += cnt;}void append(const ByteBuffer& buffer){if (buffer.size()) append(buffer.contents(),buffer.size());}void put(size_t pos, const uint8 *src, size_t cnt){assert(pos + cnt <= size() || PrintPosError(true,pos,cnt));memcpy(&mStorage[pos], src, cnt);}//
public:void print_storage(){}void textlike(){}void hexlike(){}bool PrintPosError(bool add, size_t pos, size_t esize) const{printf("ERROR: Attempt %s in ByteBuffer (pos: %u size: %u) value with size: %u",(add ? "put" : "get"), pos, size(), esize);return false;}protected:size_t                mReadPos;size_t                mWritePos;std::vector<uint8>    mStorage;
};//
// std::vector
//
#ifdef _VECTOR_
template <typename T>
ByteBuffer& operator<<(ByteBuffer& b, const std::vector<T>& v)
{b << (uint32)v.size();typename std::vector<T>::const_iterator iter    = v.begin();typename std::vector<T>::const_iterator& iEnd    = v.end();for (; iter != iEnd; ++iter){b << *iter;}return b;
}template <typename T>
ByteBuffer& operator>>(ByteBuffer& b, std::vector<T>& v)
{uint32 vsize;b >> vsize;v.clear();while (vsize--){T t;b >> t;v.push_back(t);}return b;
}
#endif//
// std::list
//
#ifdef _LIST_
template <typename T>
ByteBuffer& operator<<(ByteBuffer& b, const std::list<T>& v)
{b << (uint32)v.size();typename std::list<T>::const_iterator iter    = v.begin();typename std::list<T>::const_iterator& iEnd    = v.end();for (; iter != iEnd; ++iter){b << *iter;}return b;
}template <typename T>
ByteBuffer& operator>>(ByteBuffer& b, std::list<T>& v)
{uint32 vsize;b >> vsize;v.clear();while (vsize--){T t;b >> t;v.push_back(t);}return b;
}
#endif//
// std::map
//
#ifdef _MAP_
template <typename K, typename V>
ByteBuffer& operator<<(ByteBuffer& b, const std::map<K, V>& m)
{b << (uint32)m.size();typename std::map<K, V>::const_iterator iter = m.begin();typename std::map<K, V>::const_iterator iEnd = m.end();for (; iter != iEnd; ++iter){b << iter->first << iter->second;}return b;
}template <typename K, typename V>
ByteBuffer &operator>>(ByteBuffer& b, std::map<K, V>& m)
{uint32 msize;b >> msize;m.clear();while (msize--){K k;V v;b >> k >> v;m.insert(std::make_pair(k, v));}return b;
}
#endif

如何利用ByteBuffer序列化和反序列化
假设我们要序列化std::string的数据,那么我们这样做:

std::string str;
ByteBuffer buf;
buf << str;

那么,如何将这个str反序列化出来呢?这样做:

std::string str;
ByteBuffer buf;
buf >> str;

So Easy!是吧。具体在TCP收发包的实际场景中怎样做,我也不多废话,请看下面下载提供的代码便是了。

在实用下细节上的一些区别
通 常情况下,一个协议的数据集会定义为一个struct,然后重载其<<和>>算符用于序列化和反序列化。这个如果仅仅是在C++ 下倒还好,但如若放置在混合语言编程的情况下,这可能就不行了,很多语言是不支持算符重载的。如若纯逻辑都在lua或者python神马里面做,我们只能 为每个基本类型写一个read和write的方 法:readInt8,readInt16,,readString,writeInt8,writeInt16,writeString等等。然后在每 个协议处理方法里面按照顺序逐个的处理协议数据集的数据,这样是很容易出问题的,却也是没有办法的办法了。

Google Protocol Buffer(ProtoBuf)
在 开源工具里面,不得不提到的就是它了,它很适合于混合语言的情况下使用。它自己有一套自己的数据描述语言,数据序列化的描述都写在.proto。只需要写 一次.proto文件,便可以在多语言里面使用了该协议了。比如,我曾经做过一个VC+Flash AS3的项目,就是用的它。如果没有它,网络协议我必须在c++里面定义一次,flash里面再定义一次,那可真真是麻烦死了,麻烦倒还是小事情,如果两 边的定义不同步的话,序列化或者反序列化就会发生错误,那可就糟糕了。
如果有多语言的需求,最好就是使用像ProtoBuf这样的解决方案。当然,如果没有跨语言的需求,还是尽量简单为好,比如上面的ByteBuffer,毕竟简单的东西自己可以比较轻松的掌控。
主页地址:http://code.google.com/p/protobuf/

代码下载:testByteBuffer.rar

EDIT:
time_t解序列化写错了,参数应该是一个传出值,为一个引用,但是我把引用符给忘记了。特此订正!

 ByteBuffer& operator>>(time_t& value)
{
value = read<time_t>();
return *this;
}

转自:http://www.cppblog.com/tx7do/archive/2011/05/07/145865.html

最简单的TCP网络封包解包(补充)-序列化相关推荐

  1. 简单自定义协议的封包和解包

    简单自定义协议的封包和解包 一.通信协议 1 百度百科的解释 2 过于简单的通信协议引发的问题 3 通信协议常见内容 1.帧头 2.设备地址/类型 3.命令/指令 4.命令类型/功能码 5.数据长度 ...

  2. TCP利用封包和解包解决“粘包”问题

    本文参考自徐晓鑫<后台开发>,给出一个可实际应用的demo,该demo核心在于封包和解包的思想,以及自定义发送.接收数据. 一.TCP粘包现象 what? TCP是个"流&quo ...

  3. 解决TCP网络传输“粘包”问题

    当前在网络传输应用中,广泛采用的是TCP/IP通信协议及其标准的socket应用开发编程接口(API).TCP/IP传输层有两个并列的协议:TCP和UDP.其中TCP(transport contro ...

  4. UNIX网络编程——解决TCP网络传输“粘包”问题

           当前在网络传输应用中,广泛采用的是TCP/IP通信协议及其标准的socket应用开发编程接口(API).TCP/IP传输层有两个并列的协议:TCP和UDP.其中TCP(transport ...

  5. 解决TCP网络传输粘包问题

    作者:杨小平  王胜开 文章出处:http://blog.csdn.net/michelsn/archive/2008/01/02/2009894.aspx 当前在网络传输应用中,广泛采用的是TCP/ ...

  6. [Python]网络打解包

    Python与C.C++交互的时候,如果进行网络消息的收发,需要讲数据打包解包为字节流. 这时候就会用到Struct模块中的pack.unpack函数 打包: PKG = ''# '!' means ...

  7. 酷派CPB升级文件封包解包

    为什么80%的码农都做不了架构师?>>>    此前入手了部酷派8730L,无奈搜遍整个互联网寻求ROOT的方法以及用了各种ROOT工具均以失败告终.于是决定研究下酷派的CPB升级文 ...

  8. Java解析银联报文_中国银联8583报文(JAVA)封包/解包/位图 相关操作源代码

    一:IS08583包介绍: ISO8583包(简称8583包)是一个国际标准的包格式,最多由128个字段域组成,每个域都有统一的规定,并有定长与变长之分. 8583包前面一段为位图,用来确定包的字段域 ...

  9. 数据封包解包协议之TCP封包解包

    数据封包协议规定:整个数据包包含2字节长度信息+数据包体.2字节长度信息包含本身着2字节.如:数据体是(abcdefg)7个字节,整体封包就是09abcdefg,总共是9个字节的协议 1.netbus ...

  10. Python:简单的TCP网络编程

    最近在看<Python核心编程(第3版)>这本书,第二章网络编程看完原理是懂了,但具体每一行代码都干了些什么还是有点懵逼,结果就是,脱离了这本书就完全不会写了,或者写完运行各种报错.所以自 ...

最新文章

  1. python库datetime的使用
  2. 寻找阿姆斯特朗数c语言程序,C程序检查阿姆斯特朗数
  3. 同感,C#对JSON序列化和反序列化有点蹩脚
  4. 实战SSM_O2O商铺_04自下而上逐步整合SSM
  5. MQTT协议通俗讲解
  6. 阿里云边缘云全新架构升级,助力CDN操控新体验
  7. 2019年6月SAP发布的未来ABAP平台的发展方向
  8. 在mybatis用mysql的代码块_关于Mybatis 中使用Mysql存储过程的方法
  9. 第三篇.python编辑器和集成环境01
  10. java怎么确定数据在区间内_处理数据时,单元格内内容太多无法计数怎么破?...
  11. centos安装输入法
  12. linux 网络编程与 windows 网络编程
  13. 傅里叶变换对应的matlab函数,用MATLAB如何实现傅里叶变换
  14. PyKeyBoardFairy可以替代你游戏中的卡键盘和鼠标宏
  15. JMeter proxy server
  16. IE-LAB网络实验室:思科CCNP考几门?
  17. php如何除去图片水印,Phpcms v9如何去掉自带水印的解决方法
  18. 尝试 Nitrux 系统的六大理由
  19. 康佳在埃及成立合资公司发力非洲中东市场
  20. 网易云信im 的聊天记录展示

热门文章

  1. paip.提升用户体验---高性能web解决 c++ mycp 技术.
  2. paip.验证码识别---扭曲与旋转文字
  3. paip.文件搜索工具总结V2012.8.18
  4. 易方达、鹏华、京东数科基金投顾访谈
  5. 黄大刀 :机房建设主要标准规范的介绍
  6. 什么是Ⅰ类、Ⅱ类、Ⅲ类银行账户?秒懂!
  7. SQLite:关于日期的字段的优化将给Julia带来大幅效率提升
  8. 可用性SLA还不懂?看完这个故事就懂了........ | 凌云时刻
  9. 安全绳使用方法图解_儿童安全锁使用方法
  10. 【优化算法】多目标萤火虫算法(MOFA)【含Matlab源码 1595期】