第一范文网 - 专业文章范例文档资料分享平台

传奇源码分析

来源:用户分享 时间:2025/11/21 3:49:51 本文由loading 分享 下载这篇文档手机版
说明:文章内容仅供预览,部分内容可能不全,需要完整文档或者需要复制内容,请下载word后使用。下载word有问题请添加微信号:xxxxxxx或QQ:xxxxxx 处理(尽可能给您提供完整文档),感谢您的支持与谅解。

4) RecalcAbilitys 设置玩家的能力属性(攻击力(手,衣服),武器力量等)。

5) 循环处理本游戏玩家的附属物品,把这些物品的力量加到(手,衣服等)的攻击力量里。

6) RM_CHARSTATUSCHANGED消息,通知玩家状态改变消息。 7) AddProcess(this, RM_ABILITY, 0, 0, 0, 0, NULL); 等级 AddProcess(this, RM_SUBABILITY, 0, 0, 0, 0, NULL);

AddProcess(this, RM_DAYCHANGING, 0, 0, 0, 0, NULL); 校时 AddProcess(this, RM_SENDUSEITEMS, 0, 0, 0, 0, NULL); 装备 AddProcess(this, RM_SENDMYMAGIC, 0, 0, 0, 0, NULL); 魔法 SysMsg(szMsg, 1) 攻击力

并把用户数据从g_xReadyUserInfoList2列表中删除。

说明:

一旦通过验证,就从验证列表中该玩家,改变玩家状态,LoadPlayer加载用户资源(地图中加入用户信息,向用户24*24区域内的块内玩家发送上线消息GameSrv广播新玩家上线(坐标)的消息。向该新玩家发送玩家信息(等级,装备,魔法,攻击力等)。 传奇源码分析(2)(C++)

2010年01月30日 星期六 下午 11:04

传奇源码分析-服务器端(LoginGate服务器处理) LoginGate服务器 服务器端:

1.首先从LoginGate.cpp WinMain分析:

1) CheckAvailableIOCP : 检查是不是NT,2000的系统(IOCP) 2) InitInstance: 初始化界面,加载WSAStartup 3) MainWndProc窗口回调函数.

2.MainWndProc.CPP中分析回调函数MainWndProc switch (nMsg) {

case _IDM_CLIENTSOCK_MSG: case WM_COMMAND: case WM_CLOSE:

g_ssock Local 7000游戏登陆端口

g_csock Remote 5000 发送到logsrv服务器上的套接字

1)_IDM_CLIENTSOCK_MSG 消息:处理与logsrv回调通讯事件。 调用:OnClientSockMsg,该函数是一个回调函数:

当启动服务之后,ConnectToServer函数将

(_IDM_CLIENTSOCK_MSG消息 FD_CONNECT|FD_READ|FD_CLOSE)传入

WSAAsyncSelect函数。在与hWnd窗口句柄对应的窗口例程中以Windows消息的形式接收网络事件通知。函数OnClientSockMsg,主要完成与logsrv服务器之间的通信(心跳,转发客户端数据包等) switch (WSAGETSELECTEVENT(lParam))

{

case FD_CONNECT: case FD_CLOSE: case FD_READ:

FD_CONNECT:(重新连接情况)

A. CheckSocketError返回正常时:

a). ConnectToServer函数首先在服务启动的时候执行一次。回调 FD_CONNECT

b).连接logsrv时,开启ThreadFuncForMsg线程,把从客户端发送的数据(g_xMsgQueue, FD_READ事件读到的logSrv服务器发来的数据) 投递I/O,利用IOCP模型,发送到客户端。SleepEx挂起线程。至到一个I/O 完成回调函数被调用。 一个异步过程调用排队到此线程。

ThreadFuncForMsg线程检测(从logSrv收到的g_xMsgQueue数据包-心跳,处理包)。i/o 投递,利用IOCP发送给客户端。

if (nSocket = AnsiStrToVal(pszFirst + 1)) //得到socket WSASend((SOCKET)nSocket, &Buf, 1, &dwSendBytes, 0, NULL,

c).终止定时器_ID_TIMER_CONNECTSERVER

KillTimer(g_hMainWnd, _ID_TIMER_CONNECTSERVER); d).设置_ID_TIMER_KEEPALIVE定时器 (心跳数据包) SetTimer(g_hMainWnd, _ID_TIMER_KEEPALIVE

调用定时器回调函数OnTimerProc: 定时发关心跳数据包到logsrv服务器。SendExToServer(PACKET_KEEPALIVE);

B. 如果socket断开,设置_ID_TIMER_CONNECTSERVER定时器 ConnectToServer尝试重新连接服务器。

_ID_TIMER_CONNECTSERVER, (TIMERPROC)OnTimerProc); FD_CLOSE:

断开与logsrv服务器SOCKET连接,

OnCommand(IDM_STOPSERVICE, 0); 回调函数处理IDM_STOPSERVICE。 FD_READ:

接收logsrv服务器发送的数据包(心跳,登陆验证,selCur服务器地址),把数据加入缓冲区(g_xMsgQueue)中。

2)WM_COMMAND:

IDM_STARTSERVICE: 启动服务(IOCP模型Server响应客户端请求) IDM_STOPSERVICE: 停止服务(IOCP模型Server) 3)WM_CLOSE:

IDM_STOPSERVICE: 停止服务(IOCP模型Server) WSACleanup();

PostQuitMessage(0); //WM_DESTROY消息

IDM_STARTSERVICE: 启动服务(IOCP模型Server响应客户端请求)

InitServerSocket:函数: 1) AcceptThread线程:

Accept之后生成一个CSessionInfo对象,pNewUserInfo->sock = Accept; 客户端Socket值赋值给结构体。记录客户相关信息。

新的套接字句柄用CreateIoCompletionPort关联到完成端口,然后发出一个异步的WSASend或者WSARecv调用(pNewUserInfo->Recv();接收客户端消息),因为是异步函数,WSASend/WSARecv会马上返回,实际的发送或者接收数据的操作由WINDOWS系统去做。然后把CSessionInfo对象加入g_xSessionList中。向logsrv服务器发送用户Session信息。打包规则‘%0socket/ip$\\0’ 在客户accept之后,总投递一个I/O(recv),然后把相应的数据发往logsrv服务器。

2) CreateIOCPWorkerThread函数:

调用CreateIoCompletionPort 并根据处理器数量,创建一个或多个ServerWorkerThread线程。

ServerWorkerThread线程工作原理:

循环调用GetQueuedCompletionStatus()函数来得到IO操作结果。阻塞函数。当WINDOWS系统完成WSASend或者WSArecv的操作,把结果发到完成端口。GetQueuedCompletionStatus()马上返回,并从完成端口取得刚完成的

WSASend/WSARecv的结果。然后接着发出WSASend/WSARecv,并继续下一次循环阻塞在GetQueuedCompletionStatus()这里。

a). pSessionInfo为空或者dwBytesTransferred =0 ,在客户端close socket,发相应数据包(异常)到logsrv服务器(X命令-数据包),关闭客户端套按字。 b). while ( pSessionInfo->HasCompletionPacket() ) 如果数据验证正确,就转发数据包(A命令-数据包) logsrv服务器。 c). if (pSessionInfo->Recv() 继续投递I/O操作。 总结:

我们不停地发出异步的WSASend/WSARecv IO操作,具体的IO处理过程由WINDOWS系统完成,WINDOWS系统完成实际的IO处理后,把结果送到完成端口上(如果有多个IO都完成了,那么就在完成端口那里排成一个队列)。我们在另外一个线程里从完成端口不断地取出IO操作结果,然后根据需要再发出WSASend/WSARecv IO操作。

IDM_STOPSERVICE: 停止服务(IOCP模型Server响应客户端请求)

Close -> OnCommand(IDM_STOPSERVICE, 0L); ->g_fTerminated = TRUE; 线程退出。

if (g_hAcceptThread != INVALID_HANDLE_VALUE) {

TerminateThread(g_hAcceptThread, 0);

WaitForSingleObject(g_hAcceptThread, INFINITE); //IOCP的Accept线程

CloseHandle(g_hAcceptThread);

g_hAcceptThread = INVALID_HANDLE_VALUE; }

if (g_hMsgThread != INVALID_HANDLE_VALUE) {

TerminateThread(g_hMsgThread, 0); //窗口例程网络事件回调线程 WaitForSingleObject(g_hMsgThread, INFINITE); CloseHandle(g_hMsgThread);

g_hMsgThread = INVALID_HANDLE_VALUE; }

ClearSocket(g_ssock); ClearSocket(g_csock); CloseHandle(g_hIOCP);

总结:

LoginGate(登录网关服务器),接受客户端连接,并且把用户ID,密码直接发送到LoginSvr服务器中,由LoginSrv服务器验证之后,发送数据包返回给客户端。LoginGate之间是通过定时器,定时发送“心跳”数据。验证服务器存活的。客户端与服务器端的数据在传输中,是进行过加密的。

向loginSrv发送‘%A’+Msg+‘$0’消息: 转发客户端消息。

‘%X’+Msg+‘$0’消息: 发送用户连接消息,增加到用户列表。

‘%O’+Msg+‘$0’消息: 发送用户上线消息。

主要流程:

服务启动后,LoginGate启动了AcceptThread,和ServerWorkerThread线程,AcceptThread线程接收客户端连接,并把session信息发送给loginSrv服务器,ServerWorkerThread线程从完成端口取得刚完成的WSASend/WSARecv的结果后,把客户端数据转发给loginSrv服务器。服务启动时,WSAAsyncSelect模型连接到loginSrv服务器中。一旦连接成功,就启动ThreadFuncForMsg线程,该线程从g_xMsgQueue(FD_READ事件读到的loginSrv服务器发来的数据)中取出

loginSrv服务器处理过的数据。投递I/O,利用IOCP模型,发送到客户端。 ServerWorkerThread转发客户端数据 -> WSAAsyncSelect的Read读loginSrv处理后返回的数据-> ThreadFuncForMsg线程,投递WSASend消息,由Windows处理(IOCP),发送数据给客户端。

传奇源码分析-服务器端(LoginSvr服务器分析) LoginSvr服务器

g_gcSock Local 5500端口

1.首先从LoginSvr.cpp WinMain分析:

1) CheckAvailableIOCP : 检查是不是NT,2000的系统(IOCP) 2) InitInstance: 初始化界面,加载WSAStartup

GetDBManager()->Init( InsertLogMsg, \\

搜索更多关于: 传奇源码分析 的文档
传奇源码分析.doc 将本文的Word文档下载到电脑,方便复制、编辑、收藏和打印
本文链接:https://www.diyifanwen.net/c6l2ye1oaqr0fluh9bay7_3.html(转载请注明文章来源)
热门推荐
Copyright © 2012-2023 第一范文网 版权所有 免责声明 | 联系我们
声明 :本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
客服QQ:xxxxxx 邮箱:xxxxxx@qq.com
渝ICP备2023013149号
Top