• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

网关uid管理

相关文章 海叔叔 4年前 (2021-11-16) 48次浏览 已收录 0个评论

网关uid管理
1)笔记

1)上一节课我们完整的讲完了游客登录,登录成功以后,我们说过,网关有一个uid的管理,
我们需要注意: 因为对于我们的游戏服务器而言,所有的数据包都是网关转过来的,那么
网关怎么知道是哪个用户转的,那么这个时候,当我们的用户登录成功以后,我们会把这个
用户唯一的uid,和session对应起来,让在我们的网关内有一个对应,
我们的client_session_uid,同时我们要把这个uid保留在client_sessions_uid里面,
所以等下次它发过来一个另外的命令以后,要求一个用户已经登录验证过,所以这里的uid就
表示用户的id,到时候我们把这个uid转给我们的服务器,这个时候我们的服务器就知道是哪个,
根据这个utag,知道是哪个用户拿到了这个uid;

2)所以这个时候,我们今天完成的功能是: 当我们登录成功以后,我们要把当前这个session和这个
uid进行连接,那这个时候呢,我们登录了以后,我们前面讲过,我们的uinfo最后一个参数带了一个uid,
所以我们就要解码解出来,解出来以后,我们再把这个uid给它拿到,这个时候我们就会把
uid这个数据保存到我们这个网关这个session里面来,这样子client_session登录验证了以后,
它就保留了这个uid,下一次这个端口发送这个数据,都将是严格意义的,有效的,表示已经登录
验证过了

3)而我们 gateway这个send_to_server 的参数是raw_cmd,是没有解开的,也就是只解
出了stype,ctype,utag,并没有把整个整个解开,所以我们要在RawCmd这里添加一个接口,
把它的数据解出来, read_body,来解码包里面的内容: 数据body

4)json: 直接push (const char*)msg->body
protobuf: 把二进制解码为一个lua数据表push一下. protobuf到lua table整个过程

5)只在一个文件中看到的方法: 加static修饰;
要想把一个cc A文件中定义的方法给另外一个cc B中使用,那么就去掉static,同时在B中extern A的这个方法,如果没生命,也可以在B中不加extern;

6)登录的req res,首先我们是:send_to_client,我们是服务器往客户端转发,
在local stype, ctype, utag = RawCmd.read_header(raw_cmd),你到底使用uid作为key,还是用
临时的utag作为key, 我们之前纠结了很久,这次我们加好.

7)详细理解: send_to_client 网关转发给客户端时,utag还是uid的解决:
(1)如果你这个命令是登录返回的命令, is_login_return_cmd(ctype),我们就要做对应的处理,
什么算是登录返回的命令呢? ctype == Cmd.eGuestLoginRes 就是登录返回的,
后续有其它的登录我们后续加上就ok了

(2)如果是登录返回的命令,我们就要解出这个数据body,因为要读取登录里面所带的这个uid,
于是呢,我们通过RawCmd.read_body(raw_cmd)就解出了这个body,
解出来以后,就是GuestLoginRes, UserCenterInfo,
还要判断一下body的status是不是成功了,
不Response.OK:则没有uinfo,在client_sessions_ukey[utag],拿到client_session,直接发给客户端;

ok: 得到uid,开始判断是否有重复登录,
client_sessions_uid[uid] and client_sessions_uid[uid] ~= client_session,则说明上一个已经
有一个客户端连在这里了,并且属于这个uid,则: 发送重复登录的回应,并关闭之前session,被冲掉,
{Stype.Auth, Cmd.eRelogin, 0, nil}, Session.send_msg(client_sessions_uid[uid], relogin_cmd)
Session.close(client_sessions_uid[uid])关闭session,
client_sessions_uid[uid] = nil

保留现在重新登录的uid,重新设置:
client_sessions_uid[uid] = client_session ( 这个是从client_sessions_ukey哪里拿到的),
Session.set_uid(client_session, uid) (js是直接client_session.uid = uid这样设置),
从此: 我们可以从session知道uid,也可以从uid找到client_session

回给客户端,但是有个问题,我们不要把这个uid给客户端,先把uid清零,再发给客户端:
也就是不直接发raw_cmd了, 发:
body.uinfo.uid = 0
local login_res = {stype, ctype, 0, body}
Session.send_msg(client_session, login_res)

这样子,我们就把登录命令send回去了,同时也把uid清为0了,
注意: send_msg与send_raw_msg 参数区别,
前者是一个lua 表,后者是一个raw_cmd

(3)其它的如果不是登录命令的话,直接走下面的流程,
client_session = client_sessions_uid[utag],从这拿, 此时utag就是uid了,
拿到utag后,RawCmd.set_utag(raw_cmd, 0), 设置一下raw_cmd中的utag设置为0,
然后再把这个client_session的raw_cmd通过Session.send_raw_cmd给它发出去,
这样我们就发给客户端了

(4)拿到uid后,我们判断一下是否已经有session已经登录了,在client_sessions_uid里面判断,
注意还有个client_sessions_ukey, 登录的话,都是用ukey来做的

(5)send_to_client总体流程:
如果是登录命令:
登录时候,我们引用的是临时的这个key, client_session_ukey[utag]找到client_session,
登录不成功;
登录成功,判断重复登录,踢人;
如果不是登录命令: 直接从client_sessions_uid里面拿到client_session,
数据raw_cmd里面的uid设置为0后,把设置后的raw_cmd数据转给客户端

8)思考: 不管你是正式账号还是游客登录,由于在mysql中uid是主键,插入进来后,无论如何都会生成一个uid,
因此游客账号和正式账号都是有uid的

9)思考: blake老师说的脑子中运行代码的含义,每次做完一个模块运行之前,思路已经理一遍了,

10)详解: send_to_server, 客户端转给服务器, 在这里我们又在纠结到底使用utag还是用什么,其实都很好解决,
如果你是登录命令: is_login_request_cmd(ctype), ctype==Cmd.eGuestLoginReq,
我们就走临时的key,我们就使用g_ukey生成出来utag;

否则就是uid, utag = uid, 我们RawCmd.set_utag(raw_cmd, utag) 打上utag, 直接发给服务器即可

11)避免表不断扩大的优化:
在send_to_client中, 如果是登录返回,client_sessions_ukey[utag] = nil,
等我返回后就给它删掉,

12)如果客户的uid掉线了,我们就把掉线这个事件转给对应的服务器,eUserLostConn = 4,
当我们的用户离开以后,我们就要广播给其它的服务器,我们的用户掉线了,就要广播给stype,
如果uid不等于0,则说明有这个用户,告诉服务器说我们这个用户离开了,

if uid ~= 0 then
local user_lost = {stype, Cmd.eUserLostConn, uid, nil}
Session.send_msg(server_session, user_lost)
end

这样我们每一个模块通知掉线以后,转给服务器,服务器通过处理Cmd.eUserLostConn这个命令,
检测到这个uid的连接丢失了,可以测试啦!!!

13)再次理一下整个流程:
(1)首先是收到客户端发来的数据时,我们是进入: send_to_server,
我们首先获取server_session,判断是不是登录的请求,

如果是登录的请求:
utag = Session.get_utag(client_session),
如果utag为0,,我们就从新生成一个utag,设置一下utag,
否则就把这个表client_sessions_ukey[utag] = client_session标记好,
标记好后,RawCmd.set_utag(raw_cmd, utag)设置一下这个utag,
设置好utag后,转给服务器,

如果不是登录请求,我们就是用client_session里面的uid,
local uid = Session.get_uid(client_session)
utag = uid
if utag == 0 then
return
end

这样我们就会有这个转发,转发过去,

转发过去以后,我们还有一个点, 是否加上client_sessions_uid[uid] = client_session,
但是返回后还要走这句,这是全局存在的,除非断线了才会删掉它,
暂时先注释掉,以后我们在返回时那里加了

(2)send_to_client: 当我们又收到服务器转发给客户端,就会调send_to_client,又来读这个头,
如果这个命令是登录返回的 用is_login_return_cmd判断,如:游客登录等各种,
我们就用utag找到这个client_session, client_session = client_sessions_ukey[utag],
找到后,我们就赶紧取消掉这个映射表,
如果client_session为空,直接return,
否则读内容 local body = RawCmd.read_body(raw_cmd):

如果状态不ok,直接清空下utag, 发给客户端
RawCmd.set_utag(raw_cmd, 0)
Session.send_raw_cmd(client_session, raw_cmd)

如果状态ok, body.status == Response.OK,则说明登录成功了,
首先要检查重复登录,我们来看一看是哪一个uid登录成功了,
如果前面这个uid和现在这个client_session不一致,那么就是重复登录relogin,
发送重复登录的命令给前一个session,然后把前一个session关闭:
local relogin_cmd = {Stype.Auth, Cmd.eRelogin, 0, nil}
Session.send_msg(client_sessions_uid[uid], relogin_cmd)
Session.close(client_sessions_uid[uid])
–client_sessions_uid[uid] = nil 给不给空都行

这个时候,我们的uid就有了,
但是无论如何都走下面的:
下一次你找uid的时候,就是根据登陆的时候,映射好的:
client_sessions_uid[uid] = client_session
Session.set_uid(client_session, uid)

同时body.uinfo.uid必须为0,为什么呢?因为我们要在发送给客户端的时候,
不要带上uid的信息,执行:
body.uinfo.uid = 0
local login_res = {stype, ctype, 0, body}
Session.send_msg(client_session, login_res)
把我们的stype, ctype, body转给客户端

如果是其它的,不是登录返回的,直接从这个utag里面查找,
并把这个utag标记为0,然后send给客户端:
client_session = client_sessions_uid[utag]
RawCmd.set_utag(raw_cmd, 0)

至此,我们就保存了uid和session的映射,

等下一个命令你在发过来的时候,就必须要求你登录了以后才会有,
if is_login_request_cmd(ctype) then

else
local uid = Session.get_uid(client_session)
utag = uid
if utag == 0 then
xxxx
return
end
end

xxx处查一下发现你没登录,那直接return,因此命令无效,
也就是该操作要求先登录

否则就是这个uid有了以后,就是打上这个utag,发出去转给服务器:
RawCmd.set_utag(raw_cmd, utag)
Session.send_raw_cmd(server_session, raw_cmd)

至此,我们就能够转给这个服务器了,
如果你的utag为0,说明你还没登录,命令无效,你必须先登录,才能够做

大部分操作都是走的这个,我们就知道了是哪个uid的用户转过来的数据包,
就打上了这个utag,这样子基本就可以了

同时,的那个我们有连接丢失以后,我们会把这个uid获取出来,先清空:
local utag = Session.get_utag[s]
if client_sessions_ukey[utag] ~= nil and client_sessions_ukey[utag] == s then
client_sessions_ukey[utag] = nil
Session.set_uatg(s, 0)
end

local uid = Session.get_uid(s)
if client_sessions_uid[uid] ~= nil and client_sessions[uid] == s then
client_sessions_uid[uid] = nil
end

表明这一张表里面存的是s,

接着获取server_session:
local server_session = server_session_man[stype]

接着在其它服务器接收到链接丢失这个通用命令的时候,我就知道当前这个uid的玩家丢失了这个连接

14)思考: 我们正常设置好了uid, 完成了session与uid的绑定


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:网关uid管理
喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址