Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stop netty bootstrap from listening and accepting new connetions

Tags:

java

netty

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollChannelOption;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.socket.SocketChannel;
import sun.misc.Signal;
import sun.misc.SignalHandler;

import java.net.InetSocketAddress;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

public class ReusePortServer {
  private final int port;
  private List<Channel> bindingChannels = new LinkedList<>();

  public ReusePortServer(int port) {
    this.port = port;
  }

  private void initSignals() {
    Signal.handle(new Signal("BUS"), new SignalHandler() {
      @Override public void handle(Signal signal) {
        System.out.println("signal arrived");
        closeChannels();
      }
    });
  }

  synchronized private void closeChannels() {
    for (Channel channel : bindingChannels) {
      channel.close();
    }

    bindingChannels.clear();
  }

  synchronized private void registerChannel(Channel channel) {
    bindingChannels.add(channel);
  }

  public void start() throws Exception {
    initSignals();

    EventLoopGroup group = new EpollEventLoopGroup();
    try {
      ServerBootstrap b = new ServerBootstrap();
      b.group(group)
              .channel(EpollServerSocketChannel.class)
              .option(EpollChannelOption.SO_REUSEPORT, true)
              .localAddress(new InetSocketAddress(port))
              .childHandler(new ChannelInitializer<SocketChannel>(){
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                  ch.pipeline().addLast(new ReusePortHandler());
                  registerChannel(ch);
                }
              });

      for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
        System.out.println(e.toString());
      }
      ChannelFuture f = b.bind().sync();
      log(String.format("%s started and listen on %s", ReusePortServer.class.getName(), f.channel().localAddress()));
      // registerChannel(ch);  // ---------------I also tried to register this channel, but after my signaling, it closes my client's connection, rather than keeping it.
      f.channel().closeFuture().sync();
    } finally {
      group.shutdownGracefully().sync();
    }
  }

  private final static SimpleDateFormat datefmt = new SimpleDateFormat("HH:mm:ss ");

  public static void log(final String msg) {
    System.out.print(datefmt.format(new Date()));
    System.out.println(msg);
    System.out.flush();
  }

  public static void main(final String[] args) throws Exception {
    int port = 12355;
    new ReusePortServer(port).start();
  }
}

Hi, I am looking a way to stop netty from listening and accepting on server socket, but to finish up any ongoing job on current connections.

I come across the following question: How to stop netty from listening and accepting on server socket

and according to it, I wrote the above code, which receive signal (kill -7) to do the closing.

But the result is not expected, it closes the tcp connections, and netty can still accept new connection.

Do I use the correct way of stop netty from listening and accepting?

What's wrong here?

like image 891
Alex Avatar asked Jun 07 '16 09:06

Alex


2 Answers

You should close the ServerChannel like this:

ChannelFuture f = b.bind().sync();
// Call this once you want to stop accepting new connections.
f.channel().close().sync();
like image 100
Norman Maurer Avatar answered Oct 14 '22 12:10

Norman Maurer


I've spent about two days about this problem. I try this, and it work for me :

First, I declare:

static ChannelFuture future;

Then, when I bind port, I assign future variable:

ServerBootstrap b = new ServerBootstrap(); 
b.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ServerInitializer())
                .option(ChannelOption.SO_BACKLOG, NetUtil.SOMAXCONN)
                .childOption(ChannelOption.SO_KEEPALIVE, true);

future =  b.bind(WS_PORT).sync();

Final, I add a function to handler event when web application stop.

@PreDestroy
void shutdownWorkers() throws InterruptedException {
    future.channel().close().sync();
}
like image 2
Do Minh Phong Avatar answered Oct 14 '22 14:10

Do Minh Phong