断线重连总结

来源:互联网 发布:淘宝店类目怎么改 编辑:程序博客网 时间:2024/05/17 06:54


断线重连总结


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能正确的返还给
正确的客户端,那么重连的目标就达到了。 
原创粉丝点击