网关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,来解码包里面的内容: 数据body4)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
endxxx处查一下发现你没登录,那直接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)
endlocal 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的绑定