设计一个或几个类来解读数据:
部分实现:
class EnCode
{
private:
char un[2]{};//解决内存对齐
public:
char index = 0;
char op = 0;
union
{
char dataPool[0x8];
int lenth;
char byte;
short stval;
int val;
float fval;
double dbval;
long long lval{};
};
char* pointer= 0;
public:
EnCode(char* &buff, unsigned &len, char EnIndex=0);
~EnCode();
};
暂时设置的解析方式
DATA_DESC data_desc[2][9]{};
void init_datadecs()
{
data_desc[0][0] = { "none",0 };
data_desc[0][1] = { "short",2 };
data_desc[0][2] = { "int",4 };
data_desc[0][3] = { "int64",8 };
data_desc[0][4] = { "float",4 };
data_desc[0][5] = { "int64",8 };
data_desc[0][6] = { "char",1 };
data_desc[0][7] = { "wchar_t*",4 };
data_desc[0][8] = { "int64",8 };
data_desc[1][0] = { "none",0 };
data_desc[1][1] = { "short",2 };
data_desc[1][2] = { "int",4 };
data_desc[1][3] = { "int64",8 };
data_desc[1][4] = { "float",4 };
data_desc[1][5] = { "int64",8 };
data_desc[1][6] = { "char*",4 };
data_desc[1][7] = { "wchar_t*",4 };
data_desc[1][8] = { "int64",8 };
}
主要字符编码转化容易掉大坑
bool OnloginOk(char*& buff, unsigned& len)
{
CStringA txt;
CStringA tmp;
CString utmp;
PDATALOGINOK _p = (PDATALOGINOK)&buff[1];
if (_p->RoleCount > 0)
{
char* buffStart = buff + 1 + sizeof(DATA_LOGIN_OK);
char* buffEnd = buff + len;
while (buffStart < buffEnd)
{
EnCode* _coder = new EnCode(buffStart, len);
tmp.Format("[%s]", data_desc[_coder->index][_coder->op].name);
txt = txt + tmp;
if (_coder->op == 0x7)
{
utmp = (wchar_t*)_coder->pointer;
tmp = utmp;
txt = txt + tmp;
}
else
if (_coder->op == 0x3)
{
tmp.Format("[%f]", _coder->fval);
txt = txt + tmp;
}
else {
tmp.Format("[%d]", _coder->val);
txt = txt + tmp;
}
}
myAnly->sendData(MTYPE::I_DIS, 0, txt.GetBuffer(), txt.GetAllocLength()+1);
}
return true;
}
已经能粗略解析出来了
然后就要把这个东西定义成一个结构体
这个结构体不能直接这样写
直接定义将来处理的时候不好处理,比较好的方法就是用现在这个结构体去派生一个类,在派生类里实现自己的类型,要是之后模拟数据涉及到数据打包,结构体里有数据的内容就直接一步到位包回去了
class GBYTE :public EnCode
{
using EnCode::EnCode;//调用构造
public:
operator char();
};
class GSHORT :public EnCode
{
using EnCode::EnCode;//调用构造
public:
operator short();
};
class GINT :public EnCode
{
using EnCode::EnCode;//调用构造
public:
operator int();
};
class GFLOAT :public EnCode
{
using EnCode::EnCode;//调用构造
public:
operator float();
};
class GINT64 :public EnCode
{
using EnCode::EnCode;//调用构造
public:
operator long long();
};
class GDOUBLE :public EnCode
{
using EnCode::EnCode;//调用构造
public:
operator double();
};
class GCAHR :public EnCode
{
using EnCode::EnCode;//调用构造
public:
operator const char* ();
};
class GUTF16 :public EnCode
{
using EnCode::EnCode;//调用构造
public:
operator const wchar_t* ();
};
EnCode::~EnCode()
{
if (pointer)delete[]pointer;
//delete[] buffer;
}
GBYTE::operator char()
{
return this->byte;
}
GSHORT::operator short()
{
return this->stval;
}
GINT::operator int()
{
return this->val;
}
GFLOAT::operator float()
{
return this->fval;
}
GINT64::operator long long()
{
return this->lval;
}
GDOUBLE::operator double()
{
return this->dbval;
}
GCAHR::operator const char* ()
{
return this->pointer;
}
UTF16::operator const wchar_t* ()
{
return (wchar_t*)this->pointer;
}
直接定义类型 开始套娃
再来定义个结构体
typedef struct ROLE_DATA
{
GBYTE byte;
GINT un;
GINT un1;
GUTF16 name;
GUTF16 infos;
GINT un2;
GINT64 un3;
};
然后处理构造函数
测试下效果:
void NetClient::longinok(ROLE_DATA* roles, int count)
{
CString txt;
CString tmp;
txt.Format(L"游戏登录成功!角色数量[%d]\r\n", count);
for (int i = 0; i < count; i++)
{
tmp.Format(L"byte=%d\r\n", (char)roles[i].byte);
txt += tmp;
tmp.Format(L"un=%d\r\n", (int)roles[i].un);
txt += tmp;
tmp.Format(L"un1=%d\r\n", (int)roles[i].un1);
txt += tmp;
tmp.Format(L"name=%s\r\n", (const wchar_t*)roles[i].name);
txt += tmp;
tmp.Format(L"infos=%s\r\n", (const wchar_t*)roles[i].infos);
txt += tmp;
tmp.Format(L"un2=%d\r\n", (int)roles[i].un2);
txt += tmp;
tmp.Format(L"un3=%d\r\n", (long long)roles[i].un3);
txt += tmp;
}
AfxMessageBox(txt);
}
解析出来了
给派生类重载完运算符后,测试下(不过没啥用,测试写的)只是看看有没有用
bool OnloginOk(char*& buff, unsigned& len)
{
PDATALOGINOK _p = (PDATALOGINOK)&buff[1];
ROLE_DATA* roleDatas = nullptr;
if (_p->RoleCount > 0)
{
char* buffStart = buff + 1 + sizeof(DATA_LOGIN_OK);
winSock->AnlyBuff(buffStart,buff+len);
roleDatas = new ROLE_DATA[_p->RoleCount];//创建人物数量个解析数据
for (int i = 0; i < _p->RoleCount; i++)
{
roleDatas[i].byte=buffStart;//重载
roleDatas[i].un=buffStart;
roleDatas[i].un1=buffStart;
roleDatas[i].name=buffStart;
roleDatas[i].infos=buffStart;
roleDatas[i].un2=buffStart;
roleDatas[i].un3=buffStart;
}
}
Client->longinok(roleDatas, _p->RoleCount);//
return true;
}
解析的优化:
CStringA txt;
CStringA tmp;
CString utmp;
EnCode _coder;
GBYTE* _bytecoder;
GSHORT* _shortcoder;
GINT* _intcoder;
GFLOAT* _floatcoder;
GDOUBLE* _doublecoder;
GCHAR* _asccoder;
GUTF16* _utfcoder;
GINT64* _int64coder;
while (start < end)
{
_coder.Init(start,index);
CStringA _opname = data_desc[_coder.index][_coder.op].name;
tmp.Format("%s %s;//", data_desc[_coder.index][_coder.op].name, _opname.MakeLower());//转小写
txt = txt + tmp;
if (_coder.index == 0)
{
switch (_coder.op)
{
case 1:
_shortcoder = (GSHORT*)&_coder;
tmp.Format("%d\r\n",_shortcoder->value());
txt = txt + tmp;
break;
case 2:
_intcoder = (GINT*)&_coder;
tmp.Format("%d\r\n", _intcoder->value());
txt = txt + tmp;
break;
case 4:
_floatcoder = (GFLOAT*)&_coder;
tmp.Format("%f\r\n", _floatcoder->value());
txt = txt + tmp;
break;
case 6:
_bytecoder = (GBYTE*)&_coder;
tmp.Format("%d\r\n", _bytecoder->value());
txt = txt + tmp;
break;
case 7:
_utfcoder = (GUTF16*)&_coder;
utmp.Format(L"[%s]\r\n", _utfcoder->value());
tmp = utmp;//省的写类型转换
txt = txt + tmp;
break;
case 3:
case 5:
case 8:
_int64coder = (GINT64*)&_coder;
tmp.Format("%.i64d\r\n", _int64coder->value());
txt = txt + tmp;
break;
}
}
}
myAnly->sendData(MTYPE::I_DIS, 0, txt.GetBuffer(), txt.GetAllocLength() + 1);
这样到时候要定义结构体的时候就可以直接copy了。
接下来就要把角色数据做到类里面去维护
通过比对中间数据的字符串:
38个是等级
13是宗族
结构是 key,value;key,value;.......