How to use multiple ServerBootstrap objects in Netty

I am trying to use Netty (4.0.24) to create multiple servers (multiple ServerBootstraps) in one application (one main method). I saw this question / answer but it left many unanswered questions: Netty 4.0 with multiple ports with different protocol each port So here are my questions: The above answer assumes that all we need to do is create multiple ServerBootstrap and bind objects () for each. But most of the code examples I see for one ServerBootstrap will then call something like this:

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

      

So calling sync () doesn't block ServerBootstrap b? So how can we do this for multiple ServerBootstraps? And what happens if we don't call sync ()? Is the set of sync calls just to be able to gracefully shutdown the server using b.shutdown ()? If so, is it possible to legally close multiple ServerBootstraps?

Also, I don't understand what happens when we just call bind () without calling sync (). How does the server work? How do we close it gracefully?

Obviously, I'm pretty confused about how this all works, and unfortunately there is no Netty documentation on this. Any help would be greatly appreciated.

+3


source to share


2 answers


In the following example, you have specified and added your question to the method sync()

, here is the sample code:

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();
    }

      

So now the explanations (I try):

  • The command bind()

    creates the appropriate listening socket. It returns immediately (does not block), so the parent channel may not be available.
  • The first command sync()

    ( bind().sync()

    ) waits for the binding to complete (if an exception occurs, it jumps directly to the final part). At this point, the channel is ready and listening for new connections.
  • The team channel()

    receives this listening channel (parent, not yet connected). All clients will generate a "child" channel of this parent.
  • In your handler, after some event, you decide to close the parent channel (not the child, but the one listening and waiting for a new socket). To do this, simply call parentChannel.close()

    (or from a child channel child.parent().close()

    ).
  • The team closeFuture()

    gets a future at this closure.
  • When this future is over (done), it will happen when the last command sync()

    ( closeFuture().sync()

    ) is executed .
  • Once the parent channel is closed, you can request graceful termination of the linked channel.

So, so (waiting for closeFuture to close, then shutdownGracefully) is a clean way to shutdown all resources connected to this ServerBootstrap.



Of course, you can change the situation a little. For example, do not get the channel first, but only later when you want to block until gracefully shutdown.

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();
    }

      

This way you don't block when all 3 channels are open and then wait until all 3 are done before turning them off.

Finally, if you do not block the event bind()

, then closeFuture()

, you need to define how you will wait after commands sbx.bind()

and before that in order for ServerBootstraps to terminate.

+12


source


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();
} 

      



-4


source







All Articles