不知不觉又是三周过去了。

这几周忙了一下,其他时间全都在搞服务端,简直是酸爽的不行。。。不过还好出了些成果。

目前服务端有:

1、版本服务:游戏版本更新

2、账号服务:用户身份验证,返回各种连接(代理服务、聊天服务)

3、代理服务:获取游服列表、获取游服状态(是否需要排队)、进入游戏的验证、游服数据转发

4、队列服务:处理排队队列中用户的队列情况变化,并广播(本来这个是放在代理服务器上做的,但是我觉得广播起来有点恶心就分出来了,看起来各个服务的功能也清晰些)

5、游戏服务:游戏业务逻辑处理(作为1-n个特殊的客户端连接到代理服务器)

6、聊天服务

客户端方面,优化了一些网络通讯方面的代码,把各种消息重新整理了一遍。界面表现方面几乎没动过。

整个框架基本上实现了登录、选服、排队(等待、结束)、进入游戏、聊天。

想了一下,还是放段代码。

unit gate.handler;

interface

uses
  System.SysUtils, System.Classes, System.Math, diocp_coder_tcpServer,
  diocp_tcp_server, fol.msgcode, fol.types, fol.simpleMsgPack,
  fol.server.types, fol.server.session, gate.session, gate.cache;

procedure pushMsgData(pvMsgData: TSimpleMsgPack; pvContext: TIocpClientContext);
procedure execHeart(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext);
procedure execOffline(pvContext: TIOCPCoderClientContext);

function execRequest(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;
function execRegister(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;
function execRegisterGameServiceClient(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): string;
function execRequestServerList(pvMsgData: TSimpleMsgPack): Integer;
function execRequestServerState(const pvServerID: Integer; pvMsgData: TSimpleMsgPack): Integer;
function execRequestStartGame(const pvServerID,pvUserID: Integer;
  pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;
function execRequestGameService(pvMsgData: TSimpleMsgPack): Integer;
function execTranspond(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;

implementation

uses utils_safeLogger;

procedure pushMsgData(pvMsgData: TSimpleMsgPack; pvContext: TIocpClientContext);
var
  lvStream: TMemoryStream;
begin
  lvStream:= TMemoryStream.Create;
  try
    if Assigned(pvContext) then
    begin
      pvMsgData.Add('result',MSG_RESULT_Success);
      pvMsgData.EncodeToStream(lvStream);
      lvStream.Position:= ;
      TIOCPCoderClientContext(pvContext).WriteObject(lvStream);
    end;
  finally
    lvStream.Free;
  end;
end;

procedure execHeart(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext);
begin
  if pvContext.LockContext('keeplive', nil) then
  try
    gvSessionManager.validChecked(pvContext);
    pvMsgData.Clear;
  finally
    pvContext.UnLockContext('keeplive', nil);
  end;
end;

procedure execOffline(pvContext: TIOCPCoderClientContext);
var
  lvServerID: Integer;
  lvUserID, lvServerKey: string;
begin
  if pvContext.Data <> nil then
  begin
    {
       1. 游戏客户端: 只是连接了代理服务器,并未选服登录游戏 (断开不需要处理)
       2. 游戏客户端: 已经进入游戏的,断开需要更新对应服务器freenum
       3. OM工具: 断开不需要处理
       4. 游戏服务: 断开需要把游服记录删除(或者更新state)
    }
    lvServerID:= TClientSession(pvContext.Data).ServerID;
    lvUserID:= TClientSession(pvContext.Data).SessionID;
    case TClientSession(pvContext.Data).ClientType of
      tfctGameClient:
        begin
          sfLogger.logMessage('[INFO]: Client offline, serverid='+inttostr(lvServerID));
           then exit;
          //更新freenum(freenum+1)
          sfLogger.logMessage('[INFO]: Client offline, userid='+lvUserID);
          lvServerKey:= Format('server:%.3d',[lvServerID]);
          redisClient.HINCRBY(lvServerKey,);
          //kickOut这个session(或者设置为无效session)
          gvSessionManager.kickOutGameClient(lvUserID);
        end;
      tfctGameServiceClient:
        begin
          //更新游服列表
          lvServerKey:= Format('server:%.3d',[StrToInt(lvUserID)]);
          redisClient.DEL([lvServerKey]);
          gvSessionManager.kickOutGameService(lvUserID);
        end;
      tfctOMClient:
        begin
          sfLogger.logMessage('[INFO]: OMClient offline');
          gvSessionManager.kickOutOMClient(lvUserID);
        end;
    end;
  end;
end;

function execRegister(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;
var
  lvClientType: Integer;
  lvSessionID: string;
begin
  if pvContext.LockContext('register', nil) then
  try
    lvClientType:= pvMsgData.I['client_type'];
    case lvClientType of
      ord(tfctGameClient):
        lvSessionID:= gvSessionManager.takeAGameClientSession(pvContext, pvMsgData.S['client_id']);
      ord(tfctGameServiceClient):
        lvSessionID:= execRegisterGameServiceClient(pvMsgData, pvContext);
      ord(tfctOMClient):
        lvSessionID:= gvSessionManager.takeAOMClientSession(pvContext, pvMsgData.S['client_id']);
    end;
    pvMsgData.Clear;
    pvMsgData.S['token']:= '(gate)token_'+lvSessionID;
    result:= MSG_RESULT_Success;
  finally
    pvContext.UnLockContext('register', nil);
  end;
end;

function execRegisterGameServiceClient(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): string;
var
  lvServiceID, lvServiceName, lvServerKey, lvMaxConn: string;
begin
  lvServiceID:= pvMsgData.S['client_id'];
  lvServiceName:= pvMsgData.S['client_name'];
  lvMaxConn:= pvMsgData.S['client_maxconn'];
  result:= gvSessionManager.takeAGameServiceSession(pvContext,lvServiceID);

  //example: hmset server:001 name 五行之始 state 1 freenum 1000
  lvServerKey:= Format('server:%.3d',[StrToInt(lvServiceID)]);
  redisClient.HMSET(lvServerKey,[',lvMaxConn]);
end;

function execRequest(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;
var
  lvMsgcode, lvCallbackID, lvServerID, lvUserID: Integer;
begin
  lvMsgcode:= pvMsgData.I['msg_code'];
  lvCallbackID:= pvMsgData.I['callbackid'];
  sfLogger.logMessage('[INFO]: Receive a message package, msgcode=' + inttostr(lvMsgcode));
  case lvMsgcode of
    MSG_NET_Register: result:= execRegister(pvMsgData, pvContext);
    MSG_NET_GetServerList:
      begin
        pvMsgData.Clear;
        result:= execRequestServerList(pvMsgData);
      end;
    MSG_NET_GetServerState:
      begin
        lvServerID:= pvMsgData.I['serverid'];
        pvMsgData.Clear;
        result:= execRequestServerState(lvServerID,pvMsgData);
      end;
    MSG_NET_StartGame:
      begin
        lvServerID:= pvMsgData.I['serverid'];
        lvUserID:= pvMsgData.I['userid'];
        pvMsgData.Clear;
        result:= execRequestStartGame(lvServerID,lvUserID,pvMsgData,pvContext);
      end;
    else
      begin
        execRequestGameService(pvMsgData);
        pvMsgData.Clear;
        exit;
      end;
  end;
  pvMsgData.Add('callbackid', lvCallbackID);
end;

function execRequestServerList(pvMsgData: TSimpleMsgPack): Integer;
var
  i: Integer;
  lvServerKey: string;
  lvData: TArray<string>;
begin
    do
  begin
    lvServerKey:= Format('server:%.3d',[i]);
    lvData:= redisClient.HMGET(lvServerKey, ['name', 'state']);
    ) ]='') then break;
    pvMsgData.Add(lvData[], StrToInt(lvData[]));
  end;
  result:= MSG_RESULT_Success;
end;

function execRequestServerState(const pvServerID: Integer; pvMsgData: TSimpleMsgPack): Integer;
var
  lvServerKey: string;
  lvFreeNum: Integer;
begin
  lvServerKey:= Format('server:%.3d',[pvServerID]);
  redisClient.HGET(lvServerKey,'freenum',lvFreeNum);
  case lvFreeNum of
    : result:= MSG_RESULT_Queue;
   -: raise exception.Create('invalid freenum.');
    else result:= MSG_RESULT_Success;
  end;
end;

function execRequestStartGame(const pvServerID,pvUserID: Integer;
  pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;
var
  lvServerKey, lvQueueKey: string;
  lvFreeNum, lvState: Integer;
begin
  if pvContext.Data <> nil then
  begin
    lvServerKey:= Format('server:%.3d',[pvServerID]);
    redisClient.HGET(lvServerKey,'state',lvState);
     then raise Exception.Create('Service is Closed.');
    redisClient.HGET(lvServerKey,'freenum',lvFreeNum);
     then raise Exception.Create('Invalid request, free num is zero.');
    //
    TClientSession(pvContext.Data).ServerID:= pvServerID;
    TClientSession(pvContext.Data).State:= tusOnline;
    //更新freenum(freenum-1)
    lvFreeNum:= Max(lvFreeNum - ,);
    redisClient.HSET(lvServerKey,'freenum',lvFreeNum);
    //广播上线消息给好友
  end;
  result:= MSG_RESULT_Success;
end;

function execRequestGameService(pvMsgData: TSimpleMsgPack): Integer;
var
  lvServerID: string;
  lvContext: TIocpClientContext;
begin
  lvServerID:= IntToStr(pvMsgData.I['serverid']);
  lvContext:= gvSessionManager.findGameServiceContext(lvServerID);
  pushMsgData(pvMsgData,lvContext);
end;

function execTranspond(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;
var
  lvUserID: string;
  lvContext: TIocpClientContext;
begin
  lvUserID:= pvMsgData.S['userid'];
  lvContext:= gvSessionManager.findGameClientContext(lvUserID);
  pushMsgData(pvMsgData,lvContext);
end;

end.

【FOL】第九周的更多相关文章

  1. 第九周 psp

    团队项目PSP 一:表格     C类型 C内容 S开始时间 E结束时间 I时间间隔 T净时间(mins) 预计花费时间(mins) 讨论 讨论用户界面 9:50 12:45 35 45 80 分析与 ...

  2. PSP第九周

    一.表格 C(分类) C(内容) S(开始时间) ST(结束时间) I(打断时间) △(净工作时间) 学习 UML 12:30 13:20 0 50 编码 编码 20:00 22:10 0 130 学 ...

  3. 20145213《Java程序设计》第九周学习总结

    20145213<Java程序设计>第九周学习总结 教材学习总结 "五一"假期过得太快,就像龙卷风.没有一点点防备,就与Java博客撞个满怀.在这个普天同庆的节日里,根 ...

  4. 20145304 Java第九周学习报告

    20145304<Java程序设计>第九周学习总结 教材学习内容总结 JDBC简介 JDBC全名Java DataBase Connectivity,是Java联机数据库的标准规范.定义了 ...

  5. 21045308刘昊阳 《Java程序设计》第九周学习总结

    21045308刘昊阳 <Java程序设计>第九周学习总结 教材学习内容总结 第16章 整合数据库 16.1 JDBC入门 16.1.1 JDBC简介 数据库本身是个独立运行的应用程序 撰 ...

  6. 20145330第九周《Java学习笔记》

    20145330第九周<Java学习笔记> 第十六章 整合数据库 JDBC入门 数据库本身是个独立运行的应用程序 撰写应用程序是利用通信协议对数据库进行指令交换,以进行数据的增删查找 JD ...

  7. 20145337 《Java程序设计》第九周学习总结

    20145337 <Java程序设计>第九周学习总结 教材学习内容总结 数据库本身是个独立运行的应用程序 撰写应用程序是利用通信协议对数据库进行指令交换,以进行数据的增删查找 JDBC可以 ...

  8. 20145211 《Java程序设计》第九周学习总结——垂死病中惊坐起

    教材学习内容总结 JDBC简介 JDBC是用于执行SQL的解决方案,开发人员使用JDBC的标准接口,数据库厂商则对接口进行操作,开发人员无须接触底层数据库驱动程序的差异性 JDBC标准分为两个部分:J ...

  9. 《Java程序设计》第九周学习总结

    20145224 <Java程序设计>第九周学习总结 第十六章 整合数据库 JDBC入门 ·数据库本身是个独立运行的应用程序 ·撰写应用程序是利用通信协议对数据库进行指令交换,以进行数据的 ...

  10. 20145236 《Java程序设计》第九周学习总结

    20145236 <Java程序设计>第九周学习总结 教材学习内容总结 第十六章 整合数据库 JDBC简介 1.JDBC是java联机数据库的标准规范.它定义了一组标准类与接口,标准API ...

随机推荐

  1. MyBatis 环境搭建 (一)

    一.MyBatis简介 MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索.MyBatis 使用简 ...

  2. 使用(POI)SAX处理Excel文件,防止内存溢出

    POISAXReader h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-chi ...

  3. webpack配置详解

    webpack配置详解 先点个赞吧,再挨个点下面的连接,觉得不值这个赞的回来骂我啊. Webpack傻瓜式指南(一) Webpack傻瓜指南(二)开发和部署技巧 Webpack傻瓜式指南 原生的官网详 ...

  4. 加载的过程中图片变形了? --教你自定义自动适配图片宽高比的RatioLayout

    很多同行在开发中可能会遇到这样的问题,就是在加载图片的时候会出现图片变形的问题.其实这很可能就是你的图片宽高比和图片所在容器的宽高比不匹配造成的.比如说图片的宽为200,高为100.宽高比就是2,那么 ...

  5. AJAX大文件切割上传以及带进度条。

    分块传输的原理就是利用HTML5新增的文件slice截取函数. 代码如下: html: <input id="f" type="file" name=&q ...

  6. 关于js中值的比较规则问题

    上一篇文章提到了javascript中可变值与不可变值,如果你不知道什么是可变值和不可变值,可以先去看看那篇文章,再回来看这篇,因为这篇文章是基于可变值与不可变值讲解的. 那我就默认你知道什么是可变值 ...

  7. Visual Studio Emulator for Android 里面的安卓模拟器如何启用

    打开软件

  8. js连续指定两次或者多次的click事件(解决办法)

    setTimeout (表达式,延时时间)setTimeout(表达式,交互时间)延时时间/交互时间是以豪秒为单位的(1000ms=1s) setTimeout  在执行时,是在载入后延迟指定时间后, ...

  9. 机器学习&数据挖掘笔记_25(PGM练习九:HMM用于分类)

    前言: 本次实验是用EM来学习HMM中的参数,并用学好了的HMM对一些kinect数据进行动作分类.实验内容请参考coursera课程:Probabilistic Graphical Models 中 ...

  10. jQuery.Data源码

    jQuery.data的是jQuery的数据缓存系统.它的主要作用就是为普通对象或者DOM元素添加数据. 1 内部存储原理 这个原理很简单,原本要添加在DOM元素本身的数据,现在被集中的存储在cach ...