目录:
游戏服务器的网络分为2部分:
外网通信:服务器与客户端进行的网络数据交互。
对于使用java外网通信毋庸置疑的选择Netty。对于游戏服务器而言,Netty的外网通信只存在于网关部分。其他逻辑、数据、等仅使用内网通信组件(ZeroMQ)即可。
线程划分:
- Netty启动需要一个线程进行监听。并且监听之后需要阻塞。ch.closeFuture().sync();则会进行阻塞。这个线程主要处理socket的连接请求。新的socket建立,然后根据一定的分配逻辑将建立成功的socket连接分配到消息处理线程。
@Override
public void run() {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 启动netty监听
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 10240)
.childOption(ChannelOption.TCP_NODELAY, true)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new Decoder(), new Encoder(), new ServerHandler());
}
});
LogCore.core.info("启动监听:{}", listenPort);
// 启动
Channel ch = b.bind(listenPort).sync().channel();
ch.closeFuture().sync();
} catch (Exception e) {
throw new SysException(e);
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
- 的消息处理多线程(这里处理包括消息的接收和消息的发送),为什么消息处理需求多线程呢?这个看游戏的类型和延迟性要求,对于socket一个线程每秒可以处理的消息量也是十分巨大,记忆很多年前,我用c++的iocp单线程,每秒可以处理几十万个消息包。每秒的流量也可以达到上百M。但是虽然单个线程能处理这么大的消息量,但再大量消息包处理时会导致一定的消息延迟,特别是外挂恶意破解了消息包,然后进行大量消息包的恶意攻击。这个时候单线程的消息处理模式将会很容易导致问题。本人强烈建议使用多线程处理socket的连接。
结构解析:
对于网关的socket连接,每个连接将会封装成一个Connection对象,Connection对象的一端是负责与Clinet的通信,另外一端负责与内网的其他逻辑进行通信,这里的通信不是用Netty,而是通过ZeroMQ进行数据传输。与Zmq的通信将不在是想socket的一对一的通信,他是一种M对N模式的通信,并且逻辑上也会经常变动通信节点。比如:socket连接后,先与登录进程处理登陆请求,选择角色处理。之后角色进入场景,需要将消息转发到对应场景节点。当角色跳转场景,还能可能再次变更通信节点。具体的在zmq部分再做介绍。
内网通信:内部服务器之间的网络数据交互。