【FOL】第九周
不知不觉又是三周过去了。
这几周忙了一下,其他时间全都在搞服务端,简直是酸爽的不行。。。不过还好出了些成果。
目前服务端有:
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】第九周的更多相关文章
- 第九周 psp
团队项目PSP 一:表格 C类型 C内容 S开始时间 E结束时间 I时间间隔 T净时间(mins) 预计花费时间(mins) 讨论 讨论用户界面 9:50 12:45 35 45 80 分析与 ...
- PSP第九周
一.表格 C(分类) C(内容) S(开始时间) ST(结束时间) I(打断时间) △(净工作时间) 学习 UML 12:30 13:20 0 50 编码 编码 20:00 22:10 0 130 学 ...
- 20145213《Java程序设计》第九周学习总结
20145213<Java程序设计>第九周学习总结 教材学习总结 "五一"假期过得太快,就像龙卷风.没有一点点防备,就与Java博客撞个满怀.在这个普天同庆的节日里,根 ...
- 20145304 Java第九周学习报告
20145304<Java程序设计>第九周学习总结 教材学习内容总结 JDBC简介 JDBC全名Java DataBase Connectivity,是Java联机数据库的标准规范.定义了 ...
- 21045308刘昊阳 《Java程序设计》第九周学习总结
21045308刘昊阳 <Java程序设计>第九周学习总结 教材学习内容总结 第16章 整合数据库 16.1 JDBC入门 16.1.1 JDBC简介 数据库本身是个独立运行的应用程序 撰 ...
- 20145330第九周《Java学习笔记》
20145330第九周<Java学习笔记> 第十六章 整合数据库 JDBC入门 数据库本身是个独立运行的应用程序 撰写应用程序是利用通信协议对数据库进行指令交换,以进行数据的增删查找 JD ...
- 20145337 《Java程序设计》第九周学习总结
20145337 <Java程序设计>第九周学习总结 教材学习内容总结 数据库本身是个独立运行的应用程序 撰写应用程序是利用通信协议对数据库进行指令交换,以进行数据的增删查找 JDBC可以 ...
- 20145211 《Java程序设计》第九周学习总结——垂死病中惊坐起
教材学习内容总结 JDBC简介 JDBC是用于执行SQL的解决方案,开发人员使用JDBC的标准接口,数据库厂商则对接口进行操作,开发人员无须接触底层数据库驱动程序的差异性 JDBC标准分为两个部分:J ...
- 《Java程序设计》第九周学习总结
20145224 <Java程序设计>第九周学习总结 第十六章 整合数据库 JDBC入门 ·数据库本身是个独立运行的应用程序 ·撰写应用程序是利用通信协议对数据库进行指令交换,以进行数据的 ...
- 20145236 《Java程序设计》第九周学习总结
20145236 <Java程序设计>第九周学习总结 教材学习内容总结 第十六章 整合数据库 JDBC简介 1.JDBC是java联机数据库的标准规范.它定义了一组标准类与接口,标准API ...
随机推荐
- fir.im Weekly - 不能错过的 GitHub Top 100 开源库
好的工具&资源,会带来更多的灵感.本期 fir.im Weekly 精选了一些实用的 iOS,Android 的使用工具和源码分享,还有前端.UI方面的干货.一起来看下:) Swift 开源项 ...
- asp.net/html清理页面缓存的方法
(1) MVC BaseController: Controller内 protected override void Initialize(System.Web.Routing.RequestC ...
- DOM一致性检测
[implementation] 由于DOM分为多个级别,也包含多个部分,因此检测浏览器实现了DOM的哪些部分就十分必要.document.implementation属性就是这些提供相应信息和功能的 ...
- MIME参考列表
定义 MIME(multipurpose internet mail extensions)多用途互联网邮件扩展类型是描述消息内容类型的因特网标准.MIME消息能包含文本.图像.音频.视频以及其他应用 ...
- Netbeans不能正常启动glassfish或者部署失败不能运行的问题
错误信息:D:\临时文件\netbeans\WebTest\build\web中部署GlassFish Server 4, deploy, Connection refused: connect, f ...
- LCA算法的理解
LCA思想: 在求解最近公共祖先为问题上,用到的是Tarjan的思想,从根结点开始形成一棵深搜树,非常好的处理技巧就是在回溯到结点u的时候,u的子树已经遍历,这时候才把u结点放入合并集合中, 这样u结 ...
- Uvaoj10054 - The Necklace
/* 题意:打印欧拉回路! 思路:开始时不明白,dfs为什么是后序遍历? 因为欧拉回路本身是一条回路,那么我们在dfs时,可能存在提前找到回路,这条回路可能不是欧拉回路, 因为没有遍历完成所有的边!如 ...
- vs xamarin android 监听返回键退出程序
public override bool OnKeyDown([GeneratedEnum]Keycode keyCode, KeyEvent e) { if (keyCode == Keycode. ...
- C#预处理器指令 ,你造吗??? (●'◡'●)
什么是c#预处理指令?? 用于在 C# 源代码中嵌入的编译器命令. C#预处理器指令有哪些?? ↓↓↓这些就是预处理器指令啦 下面我们一一道来(●'◡'●) 1.#if ,#elif,#else,en ...
- Responsive Web CSS – 在线响应式布局创建器
如果您已经使用了 CSS 或前端框架,创建响应式布局应该不难. 然而,如果你刚涉足这类布局,Responsive Web CSS 可以帮助你快速上手. 这是一个基于 Web 的工具,使任何人都可以通过 ...