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

Java 如何在Netty中使用多个ServerBootstrap对象,java,netty,nio,Java,Netty,Nio,我试图使用Netty(4.0.24)在一个应用程序(一个主方法)中创建多个服务器(多个服务器引导)。我看到了这个问题/答案,但还有很多问题没有回答: 下面是我的问题: 上面的答案表明,我们所需要做的就是创建多个ServerBootstrap对象并将bind()绑定到每个对象。但是,我看到的针对单个服务器引导的大多数代码示例都会调用如下内容: try { b.bind().sync().channel().closeFuture().sync(); } finally { b.sh

我试图使用Netty(4.0.24)在一个应用程序(一个主方法)中创建多个服务器(多个服务器引导)。我看到了这个问题/答案,但还有很多问题没有回答: 下面是我的问题: 上面的答案表明,我们所需要做的就是创建多个ServerBootstrap对象并将bind()绑定到每个对象。但是,我看到的针对单个服务器引导的大多数代码示例都会调用如下内容:

try {
    b.bind().sync().channel().closeFuture().sync();
}
finally {
    b.shutdown();
}
那么sync()调用不会导致ServerBootstrap b阻塞吗?那么我们如何为多个服务器引导做到这一点呢?如果我们不调用sync(),会发生什么?这组同步调用是否仅用于使用b.shutdown()正常关闭服务器?如果是这样的话,有没有办法优雅地关闭多个服务器引导

另外,我不明白当我们只调用bind()而不调用sync()时会发生什么。服务器是否一直在运行?我们如何优雅地关闭它


很明显,我对所有这些是如何工作的感到非常困惑,不幸的是,在这方面确实缺乏令人恼火的文档。非常感谢您的帮助。

下面是您引用的示例,并添加了有关
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()
    )等待绑定完成(如果引发异常,则直接转到最后一部分)。在这一阶段,频道已经准备好,可以肯定地监听新的连接
  • channel()
    命令获取此侦听频道(父频道,尚未连接到任何人)。所有客户端将生成此父通道的“子”通道
  • 在处理程序中,在某些事件之后,您决定关闭父通道(不是子通道,而是侦听并等待新套接字的通道)。要关闭,只需调用
    parentChannel.close()
    (或从子通道
    child.parent().close()
  • closeFuture()
    命令正在获取此关闭事件的未来
  • 当此未来结束(完成)时,将执行最后一个
    sync()
    命令(
    closeFuture().sync()
  • 一旦父通道关闭,您可以请求正常关闭绑定通道
因此,这样做(等待最近的将来,然后优雅地关闭)是关闭连接到此服务器引导的所有资源的干净方法

当然,你可以改变一些事情。例如,不首先获取通道,而只是在您想要在正常关闭之前阻塞通道时才获取

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()
命令之后和关闭服务器引导之前等待。

这是已知世界历史上最棒的答案。谢谢@脑力激荡你似乎已经删除了你的问题?好的,我想你已经得到了答案;-)@FredericBrégier我这里有一个更好的问题。
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();
}