天气与日历 切换到窄版

 找回密码
 立即注册

QQ登录

只需一步,快速开始

限时开通VIP永久会员,可免费下载所有附件
查看: 371|回复: 0

[C++教程] 传奇源码分析-服务器端(LoginGate服务器处理)

[复制链接]

3188

主题

4

回帖

3290

积分

管理员

积分
3290
发表于 2024-2-26 12:05:51 | 显示全部楼层 |阅读模式
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),发送数据给客户端。





相关帖子

扫码关注微信公众号,及时获取最新资源信息!下载附件优惠VIP会员5折;永久VIP免费
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

免责声明:
1、本站提供的所有资源仅供参考学习使用,版权归原著所有,禁止下载本站资源参与商业和非法行为,请在24小时之内自行删除!
2、本站所有内容均由互联网收集整理、网友上传,并且以计算机技术研究交流为目的,仅供大家参考、学习,请勿任何商业目的与商业用途。
3、若您需要商业运营或用于其他商业活动,请您购买正版授权并合法使用。
4、论坛的所有内容都不保证其准确性,完整性,有效性,由于源码具有复制性,一经售出,概不退换。阅读本站内容因误导等因素而造成的损失本站不承担连带责任。
5、用户使用本网站必须遵守适用的法律法规,对于用户违法使用本站非法运营而引起的一切责任,由用户自行承担
6、本站所有资源来自互联网转载,版权归原著所有,用户访问和使用本站的条件是必须接受本站“免责声明”,如果不遵守,请勿访问或使用本网站
7、本站使用者因为违反本声明的规定而触犯中华人民共和国法律的,一切后果自己负责,本站不承担任何责任。
8、凡以任何方式登陆本网站或直接、间接使用本网站资料者,视为自愿接受本网站声明的约束。
9、本站以《2013 中华人民共和国计算机软件保护条例》第二章 “软件著作权” 第十七条为原则:为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。若有学员需要商用本站资源,请务必联系版权方购买正版授权!
10、本网站如无意中侵犯了某个企业或个人的知识产权,请来信【站长信箱312337667@qq.com】告之,本站将立即删除。
郑重声明:
本站所有资源仅供用户本地电脑学习源代码的内含设计思想和原理,禁止任何其他用途!
本站所有资源、教程来自互联网转载,仅供学习交流,不得商业运营资源,不确保资源完整性,图片和资源仅供参考,不提供任何技术服务。
本站资源仅供本地编辑研究学习参考,禁止未经资源商正版授权参与任何商业行为,违法行为!如需商业请购买各资源商正版授权
本站仅收集资源,提供用户自学研究使用,本站不存在私自接受协助用户架设游戏或资源,非法运营资源行为。
快速回复 返回顶部 返回列表