先上一段源代码配置,本代码采用的版本是netty5.0.0;这里主要是游戏服务器开发中netty启动时的基本配置,距离实际应用尚待测试,这里用的一些类我们在下一节进行详细解释,有如有问题可以加底部的QQ群或注册账号在本网页下提问,欢迎交流纠错,代码会进一步完善。
public class ServerManager {
private EventLoopGroup bossGroup = null; // (1)
private EventLoopGroup workerGroup = null;
//
private static EventExecutorGroup HANDER_GROUP = null;
public void startServer() {
ServerCofig serverConfig = ConfigManager.getInstance().getServerConfig();
HANDER_GROUP = new DefaultEventExecutorGroup(serverConfig.getHandlerGroup());
bossGroup = new NioEventLoopGroup(serverConfig.getBossGroup()); // (1)
workerGroup = new NioEventLoopGroup(serverConfig.getWorkGroup());
try {
ServerBootstrap b = new ServerBootstrap(); // (2)
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // (3)
.childHandler(new ChannelInitializer() { // (4)
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("decode",new MessageDecodeHandler(1024 * 1024, 4, 4));
ch.pipeline().addLast("encode",new MessageEncodeHandler());
ch.pipeline().addLast(HANDER_GROUP,"logic",new ServerLogicHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128) // (5)
.childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
// Bind and start to accept incoming connections.
ChannelFuture f = b.bind(serverConfig.getPort()).sync(); // (7)
// Wait until the server socket is closed.
// In this example, this does not happen, but you can do that to
// gracefully
// shut down your server.
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public void stop() {
int quietPeriod = 5;
int timeout = 30;
TimeUnit timeUnit = TimeUnit.SECONDS;
workerGroup.shutdownGracefully(quietPeriod, timeout, timeUnit);
bossGroup.shutdownGracefully(quietPeriod, timeout, timeUnit);
HANDER_GROUP.shutdownGracefully(quietPeriod, timeout, timeUnit);
}
}
一,EventLoopGroup
它是继承于ScheduledExecutorService线程池接口的接口,而NioEventLoopGroup就是它的一个实现类。在服务器启动时,创建两个线程池,**惯上一个叫bossGroup,一个叫workGroup,如果在构造函数中不指定创建的线程数量,会默认创建当前cpu个数的2倍个。
-
BossGroup线程:由这个线程池提供的线程是boss种类的,用于创建、连接、绑定socket,然后把这些socket传 给worker线程池。在服务器端每个监听的socket都 有一个boss线 程来处理。在客户端,只有一个boss线程来处理所有的socket。
-
WorkerGroup线程:Worker线 程执行所有的异步I/O。 他们不是通用的线程,开发人员需要注意不要把与其不同的任务赋给线程,这可能导致线程被阻塞、无法处理他们真正关心的任务,反过来会导致死锁和一些莫名其妙的性能问题。
二,ServerBootstrap
这个是整个服务器启动的服务类,代码上面从(2)到(6)都是配置一些启动所需要的参数配置。
b.group(bossGroup, workerGroup) :初始化两个线程组。
p rotected void initChannel(SocketChannel ch):添加Handler的处理链,这个是按顺序处理的。
-
添加解码处理:ch.pipeline().addLast("decode",new LengthFieldBasedFrameDecoder(1024*1024, 0, 4));
-
添加编码处理:ch.pipeline().addLast("encode",new MessageEncodeHandler());
-
添加业务逻辑Handler处理:ch.pipeline().addLast(HANDER_GROUP,"logic",new ServerLogicHandler()); HANDER_GROUP是一个事件处理线程 池:EventExecutorGroup HANDER_GROUP = new DefaultEventExecutorGroup(serverConfig.getHandlerGroup());这个配置在netty5.0的例子中有个说明:如果你的业务逻辑处理是完全异步的或处理的速度足够快,那这里可以不用配置。配置这个就是当你的业务逻辑处理Handler有比较耗时的业务时,可以让后来的请求在别的线程中执行,这样就不会阻塞,因为整个Handler链是同步的,如果其中有一个Handler因为执行耗时任务卡住了,就会阻塞后面到来的请求。
-
option()是提供给NioServerSocketChannel用来接收进来的连接。childOption()是提供给由父管道ServerChannel接收到的连接。能过添加这些配置信息,可以更改服务器的一些属性和性能。也可以通过Channle.config()配置,我会在下一篇文章中总结这些配置参数的意义,在调优时可以做个参考
-
优雅的关闭服务器:
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
这两个方法调用会等待线程池中的线程执行完毕后再退出,防止强制关闭造成正在执行的数据丢失。所以在关闭服务器的时候,不到万不得已,不要使用杀进程的方法,而应该提供一个方法,去调用这两个关闭方式。