断线重连总结

xiaoxiao2021-02-28  102

断线重连总结 gateserver负责所有与客户端的直接连接 m_conns[10000]也就是一个gateserver最多可以维持10000条socket连接,蓝月采用的是tcp 行走各种消息都是tcp,不存在丢包一说,只会延迟 每个客户端点击登录时会做以下事情 建立socket tcp连接,向gateserver 的ip port发送请求, gateserver收到后,建立连接,这时候客户端与gateserver之间socket连接成功. gateserver将这个conn(gateserver与这个客户端的连接)加入m_conns中。m_conns m_userPool, int index = m_conns.add(con), User* user = m_userPool.pop(); user.setIndex(index);//序号表示第几个连接,比如第一个玩家连进来,第二个玩家连进来,第n个玩家连进来。。。 conn->setPtr(user); //将user 与 conn对应 1 gateserver与gameserver之间的通信 当gateserver中连接进来一个用户后, 用户登录成功,获取角色等过程暂时忽略,直接进入后面游戏协议 客户端发送cm_game_pro 给gateserver,gateserver转发给gameserver 这里每个user都有一个gameconn,这个连接表示此玩家gateserver与gameserver之间用的哪个连接 因为并不是一条连接的,比如当游戏规模比较大,1个gateserver,多个gameserver, 蓝月这里默认配置是两格gameserver,一般只用一个,当一个出现问题,比如崩了或者其他原因,可以通过更改 配置,把玩家重新通过gateserver练到另一个gameserver,避免出现游戏无法进入的问题。 SERVICE_SERVER.forwardToService(SN_GAME, conn, inPacket); gateserver中GateServer是gateserver与客户端的连接,作为tcpserver. gateserver与gameserver连接中,serviceserver是作为tcpserver的,gameserver作为tcpclient gameserver与gateserver服务器启动的时候会连上, 玩家此时还没有user自己的gameconn, 第一次会分配一个,假如默认gameserver1, 那么user的gameconn就得到了,然后客户端发来的消息gateserver接收后,serviceserver通过user的gameconn发给对应的gameserver 2 gameserver的处理 收到消息放到一个消息队列,单独线程轮训此消息队列,处理 发过来的消息都会有index,这个字段表示的是,此玩家客户端对应的gateserver哪个连接, 第一次时候gameserver此时还没有此玩家的记录 gameserver维护一个m_users[10000] 对每一个新来的连接index,分配对应的m_users[index] cgindex,uid,sid都是gateser发过来的 User *user = GAME_POOL.popUser(); user->init(uid, sid); m_users[cgindex] = user; gameservice添加user就完成了, user对应一个player player就是游戏中的核心,移动,打怪,挖宝,传送,强化等所有操作都是绑定在player上面,发的消息也都是 player处理 gameservice收到消息,根据index,得到m_user[index]得到user,user->getPlayer得到player,然后player->addNetPakcet(); 然后player消息轮训处理这个netpacket,处理完 下发消息通过player对应user的 gameservice发给他的tcpserver,也就是gateserver中serviceserver,当然index也会发下去 我们知道gameserver和gateserver之间的连接只有一个, gateserver的serviceserver收到后,根据index取得m_conns[index],得到这个玩家的客户端的连接 然后下发客户端,流程结束 3 select,epoll,socket int ret = select(0, rfds, wfds, NULL, &m_timeout); 这句话的意思就是,系统监听多个socket连接,发现那个有变化就会知道,具体暂时略过 总之ret>0说明有了变化 dispatchEvent(rfds, wfds);tcp是双向的,所以读写变化都有 然后遍历这些fd集合,m_conns是一个socket连接map,map<fd,tcpconn>,一个文件句柄(socket连接也是文件句柄)对应一个tcp连接 每个连接看看 pConn->recv() pConn->onSend(); 具体就是 recv() { int error = ::recv(m_fd, m_recvBuffer+m_recvOffset, m_recvBufferSize-m_recvOffset, 0); error>0说明确实这个socket tcp连接收到了消息,那么处理这些数据,数据的解析参照之前我的博文, //解析头解析消息体等等 tcpprocessor->postMessage,把整个netpacket交给能处理的人 error==0说明有问题,连接断开了 } onSend() { int error = ::send(m_fd, m_sendBuffer+m_sendCursor, m_sendLen-m_sendCursor, 0); //大于0说明有消息可发 //等于0说明异常,连接断开了 } 之前的处理是,当异常,直接remove(pConn),然后处理一系列后续操作,玩家离线,登出等处理 TcpMultiplexor --> 维护所有tcp连接集合,处理每个conn的read write读写消息 TcpConnection --> 文件句柄(socket)->tcp连接 TcpProcessor --> 多个connection用一个processor处理  TcpAcceptor --> 每个tcpserver都有一个acceptor,就是监听器,如下 while(m_listening) { //监听线程 死循环 socket_t fd = accept(m_listenFd, sockaddr_cast(&addr_in), &len); onAccept(fd, inetaddr);//有连接 建立连接 文件句柄,inetaddress地址 pConn->bind(fd, addr, m_processors[m_nextProcessor]);//绑定端口地址 处理 //一个connection 一个processor,processor就是把连接收到的netpacket post给对应的tcpserver(例如gateserver) //然后tcpserver(gateserver)自己会轮训处理这些netpacket,头部不管,已经解析完了,只用后面的readInt等对应协议即可 m_multiplexors[m_nextMultiplexor++]->add(pConn,MASK_READ); //这个conn加入进了multiplexor 后续有了动作就可以处理了 } TcpServer --> gateserver等 4 断线重连 以上流程已经搞清楚了 断线重连也不难 两种:断开连接重新登录,断开连接不需重新登陆 当select/epoll send recv结果为0,本来连接直接断开的,现在保留60s 因为手机环境下,打电话,移动网络等很大概率很频繁会出现断网,也就是socket完全断开的情况 因此,断开不能理解就把整个connection remove掉,remove掉就是跟页游端玩家退出游戏一样, 类似妖妖平台的DOTA,断开连接 会尝试连接,1分钟连不上那么就判断完全断开,结束游戏。重新登录 时间之内,点击断线重连,这时候客户端断开之前的socket,开启新的socket连接gateserver, 连接成功,gateserver里面m_conn多了一个新的连接,找到该用户之前的conn,替换掉,同时通知gameserver m_users本来的c_gindex换位新的c_gindex, old odl client -------- gateserver   --------- gameserver --------       new 因为在时间内,没有超过60s,我不会执行remove的操作,因此这个玩家的状态还是登录状态,别人看到的他是在线的 一分钟后没连上就会真的离开游戏 新旧连接替换好之后,类似于给人接骨,练好后,客户端新的socket的消息能发给gateserver,gateserver发给gameserver, gameserver能正确的交给正确的user,player处理,下发消息gameserver能正确的交给gateserver,gateserver能正确的返还给

正确的客户端,那么重连的目标就达到了。

new

连接还是要断开的,因为epoll的边缘触发,连接断开,我没有把它从监听句柄移除的话,那么它会不停地触发事件,甚至cpu占满。应该改为,这个连接还是要从多路复用监听里面移除,但是玩家不执行logout操作,保持在线,不登出,gameserver那里逻辑层,设置玩家状态,掉线了,记录时间戳,然后当时间检测,发现掉线时间超过60秒执行logout操作,当然多线程环境下,调用函数都是使用消息,这样可以保证多线程不出问题,添加player的logout消息,。

重连的话,就是gateserver这个保留这个user,当发现收到重连的消息,找到之前的user,把之前user的gameconn设置新连接的gameconn,就行了,然后一些细节处理。(注意这里的连接值客户端与gateserver之间的连接,gameconn指gateserver与gameserver之间的连接)

转载请注明原文地址: https://www.6miu.com/read-63000.html

最新回复(0)