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

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

目前服务端有:

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. 批处理集锦——(5)使用dir查找文件

    eg dir /a-d /s /b *.bat -d表示不显示.bat结尾的文件夹

  2. 更新日志 - BugHD 新增邮件告警功能

    最近 BugHD 又新增了一些功能,包括邮件告警. issue 分享. issue 备注等,同时也做了性能优化.希望能够帮助你更高效地收集解决应用崩溃. BugHD 新增功能 1.邮件告警 除了 We ...

  3. iOS-------应用性能调优的25个建议和技巧

    性能对 iOS 应用的开发尤其重要,如果你的应用失去反应或者很慢,失望的用户会把他们的失望写满App Store的评论.然而由于iOS设备的限制,有时搞好性能是一件难事.开发过程中你会有很多需要注意的 ...

  4. javascript_core_06之正则、Math、Date

    1.RegExp:Regular Expression,创建封装正则表达式: ①正则直接量:var reg=/reg/ig:②var reg=new RegExp(“reg”,“ig”): 2.Reg ...

  5. JSP网站开发基础总结《十三》

    继上一篇为大家补充过滤器类后,本篇为大家简单介绍一下如何实现验证码效果.验证码的作用是什么呢?1.防止恶意注册2.防止恶意提交3.防止盗取账户等等,总的来说验证码的存在就是为了,防止非人为的操作,不过 ...

  6. C#调用Couchbase中的Memcached缓存

    安装服务端 服务端下载地址:http://www.couchbase.com/download 选择适合自己的进行下载安装就可以了,我这里选择的是Win7 64. 服务端安装完后,如果成功了,那么在浏 ...

  7. 使用bokeh-scala进行数据可视化(2)

    目录 前言 几种高级可视化图表 总结 一.前言        之前已经简单介绍过一次如何使用Bokeh-scala进行数据可视化(见使用bokeh-scala进行数据可视化),以及如何在Geotrel ...

  8. Testing - 测试基础 - 理解

    理解 目的 测试就是要找到关键信息,有关项目和产品的关键决策都是根据这些信息做出. 对产品质量做出总体评估. 找出并报告团队所有可能会对产品价值产生消极影响的问题(但并不意味着能发现所有问题). 重心 ...

  9. Web 开发人员和设计师必读文章推荐【系列二十九】

    <Web 前端开发精华文章推荐>2014年第8期(总第29期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...

  10. [git]撤销的相关命令:reset、revert、checkout

    基本概念 工作区 暂存区 本地版本仓库 远程版本仓库 如果不清晰上面的四个概念,请查看廖老师的git教程 这里我多说几句:最开始我使用git的时候,我并不明白我为什么写完代码要用git的一些列指令把我 ...