Java游戏服务器-Netty自动重连与会话管理
作者:网络转载 发布时间:[ 2015/11/19 10:08:06 ] 推荐标签:测试开发技术
网游少不了网络通信,不像写C++时自己造轮子,Java服务器使用Netty。Netty做了很多工作,使编写网络程序变得轻松简单。灵活利用这些基础设施,以实现我们的需求。
其中一个需求是自动重连。自动重连有两种应用场景:
· 开始连接时,对端尚未开启
· 连接中途断开
在有多个服务器(比如LoginServer和GameServer等)时,这样不用考虑服务器启动顺序。
有需求需要有解决方案,其实很简单,Netty已经提供,如下:
ctx.channel().eventLoop().schedule(() -> tryConnect(), reconnectInterval, TimeUnit.SECONDS);
tryConnect是实际执行连接的方法,后面两个参数表示每隔reconnectInterval秒重连一次即执行tryConnect,而对应上述两种应用场景的分别是connect失败和channel inactive时,详见后面代码。
自动重连解决后,还有一个问题是如何管理连接。Netty使用Channel来抽象一个连接,但实际开发时,通常逻辑上会有一个会话(Session)对象用来表示对端,可以在其上添加各种逻辑属性方法等,以及收发网络消息。这样一个Channel需要对应一个Session,且方便互相索引。
首先考虑如何创建这个Session。
为了方便Netty使用和复用,我抽象了一个TcpServer/TcpClient类分别表示服务器和客户端。理想情况是 TcpServer和TcpClient合并为一个,不同行为由Session来决定。但因为Netty的服务器和客户端分别使用ServerBootstrap和Bootstrap,其分别包含bind和connect,这个想法未能实现。
Session有两种,ListenSession负责监听连接请求,TransmitSession负责传输数据。在实际应用中,有这么一种需求,比如GameServer主动连接LoginServer,这时GameServer即作为client端。在连接成功时,需要GameServer主动发个注册消息给LoginServer,LoginServer籍此得知是哪个服务器组。此时,GameServer可能同时会以Client身份连接另一个服务器比如Gateway而且同样要发消息。那么作为client端主动连接的TransmitSession好细化,需要包含要连接的主机地址、端口和重连时间等信息,也需要在Active时发送不同消息,而Server端TransmitSession并不需要。所以设计上TransmitSession又分为ClientSession和ServerSession。SeverSession由TcpServer在建立连接时自动创建,而ListenSession和ClientSession则由使用者自行创建并交由TcpServer/TcpClient管理。
接口如下:
public abstract class ListenSession {
private boolean working = false;
private int localPort = 0;
private int relistenInterval = 10;
...
public abstract ServerSession createServerSession();
}
public abstract class TransmitSession {
protected Channel channel = null;
protected boolean working = false;
...
public abstract void onActive() throws Exception;
public abstract void onInactive() throws Exception;
public abstract void onException() throws Exception;
public abstract void onReceive(Object data) throws Exception;
public abstract void send(Object data);
}
public abstract class ClientSession extends TransmitSession {
private String remoteHost = "";
private int remotePort = 0;
private int reconnectInterval = 10;
...
}
其次考虑如何管理Channel和Session的对应关系。除了使用一个类似HashMap的容器来管理外,一个更自然的想法是直接把Session记录在Channel上好了,这样省去了每次查找的开销。Netty已经提供了,即Channel的AttrMap。这里或许有疑问的是,client端connect成功的Channel和Active/Inactive时的Channel是同一个,所以可以方便放置/取出数据。而server端bind成功的Channel放置的是ListenSession,Active/Inactive时的Channel却是一个新的,并非bind的Channel,怎么取出之前放入的ListenSession来呢?Netty也想到了,所以提供了Channel.parent()方法,每一个Active时的Channel是由bind时的Channel创建的,后者是前者的parent。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11