如何在Netty中使用多个ServerBootstrap对象

时间:2014-11-24 18:53:46

标签: java netty nio

我正在尝试使用Netty(4.0.24)在一个应用程序中创建多个服务器(多个ServerBootstraps)(一种主要方法)。我看到了这个问题/答案,但它留下了许多未回答的问题: Netty 4.0 multi port with difference protocol each port 所以这是我的问题: 上面的答案表明我们需要做的就是创建多个ServerBootstrap对象并将bind()创建到每个对象。但是我看到的单个ServerBootstrap的大多数代码示例都将调用类似这样的代码:

try {
    b.bind().sync().channel().closeFuture().sync();
}
finally {
    b.shutdown();
}

那么在ServerBootstrap b阻塞中没有sync()调用结果吗?那么我们如何才能为多个ServerBootstraps做到这一点?如果我们不调用sync()会发生什么?同步调用集是否只能通过b.shutdown()正常关闭服务器?如果是这样,有没有办法优雅地关闭多个ServerBootstraps?

另外,我不明白当我们调用bind()而不调用sync()时会发生什么。服务器是否以某种方式继续运行?我们如何优雅地关闭它?

显然,我对这一切的运作方式感到很困惑,遗憾的是Netty文档在这方面确实缺乏。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:12)

以下示例引用并在sync()方法中添加了您的问题,此处为示例代码:

EventLoopGroup bossGroup = new NioEventLoopGroup(numBossThreads);
EventLoopGroup workerGroup = new NioEventLoopGroup(numWorkerThreads);
ServerBootstrap sb1 = null;
ServerBootstrap sb2 = null;
ServerBootstrap sb3 = null;
Channel ch1 = null;
Channel ch2 = null;
Channel ch3 = null;
try {
    sb1 = new ServerBootstrap();
    sb1.group(bossGroup, workerGroup);
    ...
    ch1 = sb1.bind().sync().channel();

    sb2 = new ServerBootstrap();
    sb2.group(bossGroup, workerGroup);
    ...
    ch2 = sb2.bind().sync().channel();

    sb3 = new ServerBootstrap();
    sb3.group(bossGroup, workerGroup);
    ...
    ch3 = sb3.bind().sync().channel();
} finally {
    // Now waiting for the parent channels (the binded ones) to be closed
    if (ch1 != null) {
        ch1.closeFuture().sync();
    }
    if (b1 != null) {
        b1.shutdownGracefully();
    }
    if (ch2 != null) {
        ch2.closeFuture().sync();
    }
    if (b2 != null) {
        b2.shutdownGracefully();
    }
    if (ch3 != null) {
        ch3.closeFuture().sync();
    }
    if (b3 != null) {
        b3.shutdownGracefully();
    }

所以现在解释(我试试):

  • bind()命令创建侦听对应的套接字。它立即返回(不阻塞),因此父通道可能尚未可用。
  • 第一个sync()命令(bind().sync())等待绑定完成(如果引发异常,则直接转到finally部分)。在这个阶段,通道已经准备好并且肯定会收听新的连接。
  • channel()命令获取此侦听通道(父通道,尚未连接到任何人)。所有客户都会生成一个孩子"这个父母的渠道。
  • 在您的处理程序中,在某个事件之后,您决定关闭父通道(不是子通道,而是侦听并等待新套接字的通道)。要完成此操作,只需拨打parentChannel.close()(或从子频道child.parent().close())。
  • closeFuture()命令将在此次结束活动中获得未来。
  • 当这个未来结束(完成)时,这将是最后一次sync()命令(closeFuture().sync())的发生。
  • 关闭父通道后,您可以要求正常关闭绑定通道。

这样做(等待closeFuture然后shutdownGracefully)是一种干净的方法来关闭附加到此ServerBootstrap的所有资源。

当然你可以改变一些事情。例如,没有先获取通道,但只有在您想要在正常关闭之前阻塞之后才能获得通道。

EventLoopGroup bossGroup = new NioEventLoopGroup(numBossThreads);
EventLoopGroup workerGroup = new NioEventLoopGroup(numWorkerThreads);
ServerBootstrap sb1 = null;
ServerBootstrap sb2 = null;
ServerBootstrap sb3 = null;
ChannelFuture cf1 = null;
ChannelFuture cf2 = null;
ChannelFuture cf3 = null;
try {
    sb1 = new ServerBootstrap();
    sb1.group(bossGroup, workerGroup);
    ...
    cf1 = sb1.bind();

    sb2 = new ServerBootstrap();
    sb2.group(bossGroup, workerGroup);
    ...
    cf2 = sb2.bind();

    sb3 = new ServerBootstrap();
    sb3.group(bossGroup, workerGroup);
    ...
    cf3 = sb3.bind();
} finally {
    // Now waiting for the parent channels (the binded ones) to be closed
    if (cf1 != null) {
        cf1.sync().channel().closeFuture().sync();
    }
    if (cf2 != null) {
        c2.sync().channel().closeFuture().sync();
    }
    if (cf3 != null) {
        cf3.sync().channel().closeFuture().sync();
    }
    if (b1 != null) {
        b1.shutdownGracefully();
    }
    if (b2 != null) {
        b2.shutdownGracefully();
    }
    if (b3 != null) {
        b3.shutdownGracefully();
    }

这样你在打开所有3个频道时根本不会阻塞,但是在关闭它们之前等待所有3个频道完成。

最后,如果你不在bind()事件上阻止closeFuture()事件,那么由你决定如何在sbx.bind()之后等待命令以及关闭ServerBootstraps之前。

答案 1 :(得分:-4)

public static void main(String[] args) {
  new Thread(new Runnable(){
    @Override
    public void run() {
      //{...} ServerBootstrap 1
    }
  }).start();
  new Thread(new Runnable(){
    @Override
    public void run() {
      //{...} ServerBootstrap 2
    }
  }).start();
  new Thread(new Runnable(){
    @Override
    public void run() {
      //{...} ServerBootstrap 3
    }
  }).start();
}