我是靠谱客的博主 昏睡自行车,最近开发中收集的这篇文章主要介绍游戏服务器之消息校验3、消息编号检查,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

游戏服务器之消息校验是为了防止外挂添加的检查。


设计上:

消息校验分为

1、长度校验

消息需要过滤长度过长的消息

2、消息标识检查

消息需要过滤不符合标识的

3、校验码校验

消息需要过滤校验码不正确的

4、消息编号校验

检查编号正确的才可以转发到场景服务器,否则就踢出该玩家。编号是从0开始,到65535就重新从0开始

消息头的信息

struct base_msg
{
uint16 reserve;//保留字节(第15位是可用来标识是否压缩(0x4000))
uint16 len;//长度(从消息头标识开始计算)
uint16 base_flag;//消息头标识(某个固定的值)
uint16 base_sum;//交验码
uint16 base_index;//消息编号
uint8 first;//一级系统指令
uint8 second;//二级系统指令
...
};


1、消息头过滤

分析检验正确的才派送,然后发送到场景进程

1、长度校验
大于1.5K,小于消息头长度的包都直接忽略 (ptNull 是消息指针, msglen 消息长度)
if (!ptNull || msglen< (MSG_HEAD_SIZE) || msglen >= 1536)
{
error_log("外挂发来(帐号%s,角色(%u,%s),ip:%s):,网关消息解析消息长度出错:%u,发来的消息是(%u,%u)",
account,pplayer->id,pplayer->name,getIP(),msglen,ptNull->first,ptNull->second);
TerminateWait();
return false;
}

2、消息标识检查

网关消息标签不正确的需要忽略掉
if(MSG_HEAD_FLAG!= ptNull->base_flag)
{
error_log("外挂发来,帐号%s,角色(%u,%s),ip:%s):网关消息标签不正确,消息标签(%u %u),发来的消息是(%u,%u)",
account,pplayer->id,pplayer->name,getIP(),MSG_HEAD_FLAG,ptNull->base_flag,ptNull->first,ptNull->second);
TerminateWait();
return false;
}

3、校验码校验

消息校验码校验

if (!calcPacketVerify(ptNull,msglen))
{
error_log("外挂发来(帐号%s,角色(%u,%s),ip:%s):校验出错,发来的消息是(%u,%u)",
account,pplayer->id,pplayer->name,getIP(),ptNull->first,ptNull->second);
TerminateWait();
return false;
}


4、消息编号校验

 消息编号检查

if(!checkMsgIndex(ptNull->base_index))
{
error_log("外挂发来(帐号%s,角色(%u,%s),ip:%s):网关连接的消息报序列不正确,需要的是%u,发来的是%u,消息是(%u,%u)",
account,pplayer->id,pplayer->name,getIP(),msg_index,ptNull->base_index,ptNull->first,ptNull->second);
TerminateWait();
return false;
}


2、校验码检查

校验码是从消息体开始的(这里是从一级指令开始的,不包含消息头的消息编号之前的信息),对每个字节异或,并异或两个特殊的key(一个是写死的,一个是分配连接时随机的)。

只有前端发来的校验码是跟后端计算一样的,才算是校验码正确的。

bool gateway_session::calcPacketVerify(const MSG::base_msg *ptNull, const uint32 msglen)
{
const uint8* pBuffer = (const uint8*)ptNull+MSG_HEAD_SIZE;//消息校验从一级指令开始
uint16 dwMsgBodySize = msglen-MSG_HEAD_SIZE;//一级指令开始是消息体
uint16 ret = 0xAB;//特殊的key
const uint8 *pb = (const uint8*)pBuffer;
while (dwMsgBodySize > 0)
{
ret ^= *pb;
dwMsgBodySize--;
pb++;
}
//计算校验码
ret ^= (uint16)(loginTempID & 0xFFFF);//登录时分配的临时id作为校验的key
if(ret != ptNull->base_sum)
{
error_log("校验出错,帐号%s,校验码(正确的是%u,发来的是%u)",account,ret,ptNull->base_sum);
return false;
}
return true;
}


3、消息编号检查

消息编号是从0开始的0~65535  的消息编号,每发一个消息,消息编号都加1,到了65535就从0开始。

bool gateway_session::checkMsgIndex(uint16 msgIndex)
{
if(msg_index != msgIndex)//消息编号不正确的直接返回错误
{
return false;
}
if(msg_index == 0xffff)//到达65535的重新从0开始
{
msg_index = 0;
}
else
{
msg_index++;//严格递增
}
return true;
}



最后

以上就是昏睡自行车为你收集整理的游戏服务器之消息校验3、消息编号检查的全部内容,希望文章能够帮你解决游戏服务器之消息校验3、消息编号检查所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(30)

评论列表共有 0 条评论

立即
投稿
返回
顶部