谷歌的PB协议很强大,主要是模拟了一个宿主语言,而C++原生语言对一些代码的动态生成是很弱势的。在游戏协议上,其实很多字段虽然有定义,但是都不一定每回发送的时候都使用到。如何的去灵活定制这里面的序列化?
因为谷歌是先用宿主语言描述了一遍,把字段和flag给绑定起来,然后生成代码。而在项目中,即使再强大的代码库,还是觉得很冗余。这里的冗余指的是说,从成本上考虑,一边是一个庞大的库,一边可以自己写个简单的但是稍微复杂的,虽然麻烦点,但是理解和维护成本肯定低于前者。
针对后者,我们来做一些定制序列化的分析:
肯定做不到谷歌那样根据单独一个flag变量动态的生成,那样代码越来越复杂;
写入的时候先记录写入变量的偏移位置,然后读的时候根据偏移位置自动读取?
似乎是个好主意,但是实施的时候,会发现光有个偏移位置还不够,读取的时候还要记录大小,那么结构就变成
【偏移量,2个字节】【字段大小,2个字节】【字段值】
也就是说把一个协议体的字段独立的拆开,但是容量上似乎不太合算,每个字段都要增加4个字节。
那么换种思路考虑,既然根据打FLAG无法做到很满意的效果,那能不能从代码上考虑?比如函数有read,write,我只要写一遍 write,保持写入的流顺序,解析的时候自动反解析出来即可。我觉得这样的成本可以接受。
那么继续分析现有的代码,
write(buffer,variable,sizeof(variable)),
read(buffer,variable,sizeof(variable)),
我们发现write和read的区别其实就是buffer到variable,或者variable到buffer。那么我们可以把这个函数给抽象出来,做成虚函数,分别实现相反的读写。然后上层对其进行封装,根据行为传入不同的参数:
class CIProtocolSerialLite
{
public:
virtual char* Serial(char* pBuffer, char* pVariable, int nVariableSize)=0;
private:
public:
private:
};
class CProtocolSerialLiteSend:public CIProtocolSerialLite
{
public:
//pVariable拷贝到pBuffer
virtual char* Serial(char* pBuffer, char* pVariable, int nVariableSize);
private:
public:
private:
};
class CProtocolSerialLiteRecv:public CIProtocolSerialLite
{
public:
//pBuffer拷贝到pVariable
virtual char* Serial(char* pBuffer, char* pVariable, int nVariableSize);
private:
public:
private:
};
/*
CProtocolSerialLiteSend
*/
char* CProtocolSerialLiteSend::Serial(char* pBuffer, char* pVariable, int nVariableSize)
{
memcpy(pBuffer, pVariable, nVariableSize);
pBuffer+=nVariableSize;
return pBuffer;
}
/*
CProtocolSerialLiteRecv
*/
char* CProtocolSerialLiteRecv::Serial(char* pBuffer, char* pVariable, int nVariableSize)
{
memcpy(pVariable, pBuffer, nVariableSize);
pBuffer+=nVariableSize;
return pBuffer;
}
假如有这样一个协议体
#include "CProtocolSerialLite.h"
class CProtocolA
{
public:
CProtocolA();
bool Init();
void Send(char* pBuffer);
void Recv(char* pBuffer);
int GetSize();
void SetT1(int nValue);
void SetT2(int nValue);
void SetT3(int nValue);
private:
void Serial(CIProtocolSerialLite *pSerialLite, char* pBuffer);
public:
private:
int m_nSize; //实际发送的大小
//连续发送
int m_nT1;
int m_nT2;
int m_nT3;
};
CProtocolA::CProtocolA()
{
Init();
}
bool CProtocolA::Init()
{
m_nSize = 0;
//-1为无效值
m_nT1 = -1;
m_nT2 = -1;
m_nT3 = -1;
return true;
}
int CProtocolA::GetSize()
{
return m_nSize;
}
void CProtocolA::SetT1(int nValue)
{
m_nT1=nValue;
}
void CProtocolA::SetT2(int nValue)
{
m_nT2=nValue;
}
void CProtocolA::SetT3(int nValue)
{
m_nT3=nValue;
}
void CProtocolA::Send(char* pBuffer)
{
CProtocolSerialLiteSend SerialLiteSend;
Serial(&SerialLiteSend, pBuffer);
}
void CProtocolA::Recv(char* pBuffer)
{
CProtocolSerialLiteRecv SerialLiteRecv;
Serial(&SerialLiteRecv, pBuffer);
}
void CProtocolA::Serial(CIProtocolSerialLite *pSerialLite, char* pBuffer)
{
pBuffer=pSerialLite->Serial(pBuffer, (char*)&m_nT1, sizeof(m_nT1));
m_nSize += sizeof(m_nT1);
pBuffer=pSerialLite->Serial(pBuffer, (char*)&m_nT2, sizeof(m_nT2));
m_nSize += sizeof(m_nT2);
pBuffer=pSerialLite->Serial(pBuffer, (char*)&m_nT3, sizeof(m_nT3));
m_nSize += sizeof(m_nT3);
}
对外暴露的是send和write,接口可以根据具体的代码情况修改参数。并且在公共的Serial函数中,顺便把该协议真正的发送长度也求出来了,而且利用C++的指针也非常容易的插入到pBuffer中的任意位置(代码中无)。
如果只要修改Serial函数,那么之前的flag所带来的好处就完全可以抵消。至于选择性的字段那就很简单啦。自己实现个flag,在Serial函数里先写入flag, 剩下根据flag函数进行读取的代码都是一摸一样的
分享到:
相关推荐
Protocol Buffer序列化对比Java序列化.
Google Protocol Buffer 详细入门Google Protocol Buffer 详细入门
Protocol Buffer 2.5.0 jar包
关于 Google Protocol Buffer的2.5.jar和 proto.exe 和IDEA的Proto插件。在开发中可以让你们省很多时间,直接通过IDEA编译Proto文件,超级方便
包含protobuf-java-2.5.0.jar、 protoc.exe 、msg.proto、Compile.bat可供生成java和c++的协议文件。使用时可修改msg.proto文件定义自己的协议格式。只需要点击Compile.bat即可生成Msg.java和msg.pb.h msg.pb.cc三个...
google Protocol Buffer学习文档。提供相关资料,帮助您快速上手
Protocol Buffers是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化...它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了C++、Java、Python三种语言的API。
Apple 团队开源的基于 Google Protocol Buffer ("protobuf") 序列化技术的运行时库.zip,使用protobuf和swift的插件和运行库
反序列化:Protocol buffers 反序列化 需要转换到16进制,一键反序列化,有问题可以私信我
Google protocol buffer 2.3.0版源码+编译器 可用VS2008编译
谷歌公司开发的protocol序列化文件时使用,目前大数据hadoop中用来序列化保存数据
Protocol Buffers被定义为一种数据描述语言(Data Description Language,DDL),广泛的应用于Google内部,用于结构化数据的描述、传输和存储。尽管其功能和用途与XML基本相似,但是 Protocol Buffers更为轻便。...
protocolbuffer案例代码
Protocol Buffer使用
用Java语言实现的利用Protocol Buffer进行数据保存的实例,具体的体现是一个学生记录管理。一个Demo,为了帮大家理解Protocol Buffer的。
Python调用序列化数据工具Protocol Buffers——protobuf https://xercis.blog.csdn.net/article/details/109204030
C++实例Protocol Buffer技术详解,感兴趣的朋友可以了解下