【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 ...
随机推荐
- Atitit 循环(loop), 递归(recursion), 遍历(traversal), 迭代(iterate).
Atitit 循环(loop), 递归(recursion), 遍历(traversal), 迭代(iterate). 1.1. 循环算是最基础的概念, 凡是重复执行一段代码, 都可以称之为循环. ...
- 通过bootstrap来学习less
很早之前就听说过less了,但是一直拖着没去学习.最近抽空看了less,其实语法很简单,看一遍基本就知道怎么用了.平时自己写页面用less的话,感觉是方便了些,但是难道less的好处就只是这样? 刚好 ...
- javascript基础语法——变量和标识符
× 目录 [1]定义 [2]命名规则 [3]声明[4]特性[5]作用域[6]声明提升[7]属性变量 前面的话 关于javascript,第一个比较重要的概念是变量,变量的工作机制是javascript ...
- java 模拟qq源码
java 模拟qq源码: http://files.cnblogs.com/files/hujunzheng/QQ--hjzgg.zip
- PHP 字符串函数
字符串是字符序列,比如 "Hello world!". PHP 字符串函数 在本节中,我们将学习常用的字符串操作函数. PHP strlen() 函数 strlen() 函数返回字 ...
- AngularJS in Action读书笔记4(实战篇)——创建Statistic模块
个人感觉<Angularjs in action>这本书写的很好,很流畅,循序渐进,深入浅出,关键是结合了一个托管于Github上的实例讲解的,有代码可查,对于初学者应该是个不错的途径.( ...
- 优秀工具推荐:超实用的 CSS 库,样板和框架
当启动一个新的项目,使用 CSS 框架或样板,可以帮助您节省大量的时间.在这篇文章中,我编译整理了我最喜欢的 CSS 样板,框架和库,帮助你在建立网站或应用程序时更加高效. 您可能感兴趣的相关文章 精 ...
- Java线程并发中常见的锁
随着互联网的蓬勃发展,越来越多的互联网企业面临着用户量膨胀而带来的并发安全问题.本文着重介绍了在java并发中常见的几种锁机制. 1.偏向锁 偏向锁是JDK1.6提出来的一种锁优化的机制.其核心的思想 ...
- 【原创】Django-ORM基础
概述 1.什么是ORM? ORM,即Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候,就不 ...
- Struts2 源码分析——调结者(Dispatcher)之准备工作
章节简言 上一章笔者讲到关于struts2过滤器(Filter)的知识.让我们了解到StrutsPrepareFilter和StrutsExecuteFilter的作用.特别是StrutsPrepar ...