本章继上一章交易创建之后介绍比特币客户端序列化数据的过程。
比特币客户端所有的序列化函数均在seriliaze.h中实现。其中,CDataStream类是数据序列化的核心结构。
CDataStream拥有一个字符类容器用来存放序列化之后的数据。它结合一个容器类型和一个流(stream)界面以处理数据。它使用6个成员函数实现这一功能:
class CDataStream
{
protected:
typedef vector > vector_type;
vector_type vch;
unsigned int nReadPos;
short state;
short exceptmask;
public:
int nType;
int nVersion;
//......
}
enum
{
// primary actions
SER_NETWORK = (1 << 0),
SER_DISK = (1 << 1),
SER_GETHASH = (1 << 2),
// modifiers
SER_SKIPSIG = (1 << 16),
SER_BLOCKHEADERONLY = (1 << 17),
};
CDataStream& read(char* pch, int nSize)
{
// Read from the beginning of the buffer
assert(nSize >= 0);
unsigned int nReadPosNext = nReadPos + nSize;
if (nReadPosNext >= vch.size())
{
if (nReadPosNext > vch.size())
{
setstate(ios::failbit, "CDataStream::read() : end of data");
memset(pch, 0, nSize);
nSize = vch.size() - nReadPos;
}
memcpy(pch, &vch[nReadPos], nSize);
nReadPos = 0;
vch.clear();
return (*this);
}
memcpy(pch, &vch[nReadPos], nSize);
nReadPos = nReadPosNext;
return (*this);
}
CDataStream& write(const char* pch, int nSize)
{
// Write to the end of the buffer
assert(nSize >= 0);
vch.insert(vch.end(), pch, pch + nSize);
return (*this);
}
CDataStream::read()从CDataStream复制nSize个字符到一个由char* pch所指向的内存空间。以下是它的实现过程:
#define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj))
#define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj))
template inline void Serialize(Stream& s, unsigned long a, int, int=0) { WRITEDATA(s, a); }
template inline void Serialize(Stream& s, unsigned long a, int, int=0) { s.write((char*)&(a), sizeof(a)); }
template
CDataStream& operator<<(const T& obj)
{
// Serialize to this stream
::Serialize(*this, obj, nType, nVersion);
return (*this);
}
template
CDataStream& operator>>(T& obj)
{
// Unserialize from this stream
::Unserialize(*this, obj, nType, nVersion);
return (*this);
}
CDataStream ss(SER_GETHASH);
ss<>obj3>>obj4; //反序列化
template
inline void Serialize(Stream& os, const T& a, long nType, int nVersion=VERSION)
{
a.Serialize(os, (int)nType, nVersion);
}
unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const;
void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const;
void Unserialize(Stream& s, int nType=0, int nVersion=VERSION);
#define IMPLEMENT_SERIALIZE(statements) \
unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const \
{ \
CSerActionGetSerializeSize ser_action; \
const bool fGetSize = true; \
const bool fWrite = false; \
const bool fRead = false; \
unsigned int nSerSize = 0; \
ser_streamplaceholder s; \
s.nType = nType; \
s.nVersion = nVersion; \
{statements} \
return nSerSize; \
} \
template \
void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const \
{ \
CSerActionSerialize ser_action; \
const bool fGetSize = false; \
const bool fWrite = true; \
const bool fRead = false; \
unsigned int nSerSize = 0; \
{statements} \
} \
template \
void Unserialize(Stream& s, int nType=0, int nVersion=VERSION) \
{ \
CSerActionUnserialize ser_action; \
const bool fGetSize = false; \
const bool fWrite = false; \
const bool fRead = true; \
unsigned int nSerSize = 0; \
{statements} \
}
#include
#include "serialize.h"
using namespace std;
class AClass {
public:
AClass(int xin) : x(xin){};
int x;
IMPLEMENT_SERIALIZE(READWRITE(this->x);)
}
int main() {
CDataStream astream2;
AClass aObj(200); //一个x为200的AClass类型对象
cout<<"aObj="<>endl;
asream2<>a2
cout<<"a2="<
aObj=200
a2=200
#define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action))
template
inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action)
{
return ::GetSerializeSize(obj, nType, nVersion);
}
template
inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action)
{
::Serialize(s, obj, nType, nVersion);
return 0;
}
template
inline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action)
{
::Unserialize(s, obj, nType, nVersion);
return 0;
}