先做个对比:卓越版本的分布式构架,相对于之前的版本旗舰、荣耀、大众、经典、6603等版本。在分布式上做了优化,更为可靠,高效,安全。
1. 采用websocket通信,更为安全可靠,同时可以和后台直接通信,后台修改数据,在线的手机端及时同步。
2. 兼顾web端、微信小游戏,可以和C++服务器直接二进制通信,客户端使用TypeScript(JavaScript的超集),一份代码可以发布到iOS,Android,Web,WeChatGame等平台,节省了更多的开发成本。
3. 前端和服务端使用长连接,相比与之前的版本短连接,更高效,体验更好。只连接一个服务器,进入子游戏不需要断开连接,再去连接子游戏服务器,一切都是通过链接服务器内部中转。
4. 内核采用心跳机制。超过一定时间未收到前端的消息,会主动向前端放一个心跳数据,超过一段时间没有收到新的数据,就断开剔除连接。这种机制在长连接中非常有必要,防止假死连接,服务器连接资源被消耗完的情况。
5. 可以开启多个链接服务器,网站接口直接跟服务器通信,获取最佳的IP和端口,达到负载均衡的问题,又保护了服务器的IP信息。
6. 链接服务器仅仅做消息的转发,不做数据库相关的操作,也没有关键代码的操作。即便某个链接服务器所在的服务器被黑客攻陷,也不影响整个系统的正常的运行,更得不到数据库相关的信息。
综上所述,卓越的这个版本系统更为优化。但目前前端没有约占、大联盟功能。
下面来介绍逆向过程。
经过对内核引擎、LogicServerData.dll的逆向,综合前端TypeScript代码的阅读理解。对链接服务器的功能有了基本了解。
启动链接服务器,分别会去连接协调、用户状态、逻辑、约占服务器。这才算启动成功,然后又去连接子游戏服务器。
并且都有断线重连功能的。
这些功能在对应的服务器代码里也得到了印证。
协调服务器的代码
//注册链接
bool CAttemperEngineSink::OnRegisterLinkServer(VOID* pData, WORD wDataSize, DWORD dwSocketID);
用户状态服务器、逻辑服务器
//注册链接
bool CAttemperEngineSink::OnRegisterLinkServer(VOID* pData, WORD wDataSize, DWORD dwSocketID);
约战服务器、游戏服务器
//注册服务
bool CAttemperEngineSink::OnTCPNetworkMainRegister(WORD wSubCmdID, VOID* pData, WORD wDataSize, DWORD dwSocketID);
上面的几个函数有注册的具体逻辑。
下面开始IDA
这里有两个重要的类成员
//子游戏连接
protected:
CTCPSocketServiceArray m_TCPSocketServiceArray; //连接数组
CTCPSocketServiceArray m_TCPSocketServiceStore; //存储连接
用于保存子游戏的链接。
有两个关键函数,激活、删除连接
CInitParameter加载本地配置
CDlgSetPort端口选择
//更新数据
bool CDlgSetPort::FillControlToData()
{
int nTmp = GetDlgItemInt(IDC_SERVER_PORT);
if (nTmp >= 0 && nTmp<1024 || nTmp >= 0xFFFF)
{
LPCTSTR pszQuestion = TEXT("提示:端口范围1025~65534");
AfxMessageBox(pszQuestion, MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION);// != IDYES
return false;
}
m_wServicePort = (WORD)nTmp;
return true;
}
GlobalInfoManager.h
class CGlobalInfoManager
{
//索引变量
protected:
CMapGameServerID m_MapGameServerID; //房间标识
//存储变量
protected:
CGlobalGameServerItem * m_pGlobalGameServerItem; //房间存储
//函数定义
public:
//构造函数
CGlobalInfoManager();
//析构函数
virtual ~CGlobalInfoManager();
//管理函数
public:
//重置数据
VOID ResetData();
//房间数目
DWORD GetGameServerItemCount() { return (DWORD)m_MapGameServerID.GetCount(); }
//房间管理
public:
//删除房间
bool DeleteGameServerItem(WORD wServerID);
//激活房间
CGlobalGameServerItem * ActiveGameServerItem(GameServerItem & GameServer, WORD wServerID);
//服务查找
public:
//寻找房间
CGlobalGameServerItem * SearchGameServerItem(WORD wServerID);
//寻找连接
ITCPSocketService * SearchGameServerTCPSocketService(WORD wServerID);
//枚举函数
public:
CGlobalGameServerItem * EnumGameServerItem(POSITION & Position);
//创建函数
public:
//创建房间
CGlobalGameServerItem * CreateGlobalGameServerItem();
//释放函数
private:
//释放房间
bool FreeGlobalGameServerItem(CGlobalGameServerItem * pGlobalGameServerItem);
};
最重要的AttemperEngineSink部分,消息的转发
断线重连部分代码截图
还有此启动过程、断线重连、分布式服务器之间的注册、转发消息、中断连接、进入子游戏的处理等。这里不再一一详尽说明。
以上IDA很多方法的名字是我分析后,重命名的。直接通过IDA分析出来的方法没有这么好懂的,需要自己分析逻辑是干啥的,再做重命名的。
到此基本完工
预告:下一节,介绍如何搞定Cocos Creator发布后的手机端的底层(iOS,Android)