2015-01-19 16 views
12

Używam Netty 4.0.24.Final.Programowo zatrzymuje Netty

Muszę programowo uruchomić/zatrzymać serwer Netty.
Po uruchomieniu serwera, wątek zostanie zablokowany na

f.channel().closeFuture().sync()

Proszę o pomoc z niektórych wskazówek, jak to zrobić poprawnie. Poniżej znajduje się EchoServer, który jest wywoływany przez klasę Main. Dzięki.

package nettytests; 

import io.netty.bootstrap.ServerBootstrap; 
import io.netty.channel.ChannelFuture; 
import io.netty.channel.ChannelInitializer; 
import io.netty.channel.ChannelOption; 
import io.netty.channel.EventLoopGroup; 
import io.netty.channel.nio.NioEventLoopGroup; 
import io.netty.channel.socket.SocketChannel; 
import io.netty.channel.socket.nio.NioServerSocketChannel; 
import io.netty.handler.logging.LogLevel; 
import io.netty.handler.logging.LoggingHandler; 

public class EchoServer { 

    private final int PORT = 8007; 
    private EventLoopGroup bossGroup; 
    private EventLoopGroup workerGroup; 

    public void start() throws Exception { 
     // Configure the server. 
     bossGroup = new NioEventLoopGroup(1); 
     workerGroup = new NioEventLoopGroup(1); 
     try { 
      ServerBootstrap b = new ServerBootstrap(); 
      b.group(bossGroup, workerGroup) 
      .channel(NioServerSocketChannel.class) 
      .option(ChannelOption.SO_BACKLOG, 100) 
      .handler(new LoggingHandler(LogLevel.INFO)) 
      .childHandler(new ChannelInitializer<SocketChannel>() { 
       @Override 
       public void initChannel(SocketChannel ch) throws Exception { 
        ch.pipeline().addLast(new EchoServerHandler()); 
       } 
      }); 

      // Start the server. 
      ChannelFuture f = b.bind(PORT).sync(); 

      // Wait until the server socket is closed. Thread gets blocked. 
      f.channel().closeFuture().sync(); 
     } finally { 
      // Shut down all event loops to terminate all threads. 
      bossGroup.shutdownGracefully(); 
      workerGroup.shutdownGracefully(); 
     } 
    } 

    public void stop(){ 
     bossGroup.shutdownGracefully(); 
     workerGroup.shutdownGracefully(); 
    } 
} 


package nettytests; 

public class Main { 
    public static void main(String[] args) throws Exception { 
     EchoServer server = new EchoServer(); 
     // start server 
     server.start(); 

     // not called, because the thread is blocked above 
     server.stop(); 
    } 
} 

UPDATE: zmieniłem klasę EchoServer w następujący sposób. Chodzi o to, aby uruchomić serwer w nowym wątku i zachować linki do grup EventLoopGoups. Czy to właściwa droga?

package nettytests; 

import io.netty.bootstrap.ServerBootstrap; 
import io.netty.channel.ChannelFuture; 
import io.netty.channel.ChannelInitializer; 
import io.netty.channel.ChannelOption; 
import io.netty.channel.EventLoopGroup; 
import io.netty.channel.nio.NioEventLoopGroup; 
import io.netty.channel.socket.SocketChannel; 
import io.netty.channel.socket.nio.NioServerSocketChannel; 
import io.netty.handler.logging.LogLevel; 
import io.netty.handler.logging.LoggingHandler; 

/** 
* Echoes back any received data from a client. 
*/ 
public class EchoServer { 

    private final int PORT = 8007; 
    private EventLoopGroup bossGroup; 
    private EventLoopGroup workerGroup; 

    public void start() throws Exception { 
     new Thread(() -> { 
      // Configure the server. 
      bossGroup = new NioEventLoopGroup(1); 
      workerGroup = new NioEventLoopGroup(1); 
      Thread.currentThread().setName("ServerThread"); 
      try { 
       ServerBootstrap b = new ServerBootstrap(); 
       b.group(bossGroup, workerGroup) 
         .channel(NioServerSocketChannel.class) 
         .option(ChannelOption.SO_BACKLOG, 100) 
         .handler(new LoggingHandler(LogLevel.INFO)) 
         .childHandler(new ChannelInitializer<SocketChannel>() { 
          @Override 
          public void initChannel(SocketChannel ch) throws Exception { 
           ch.pipeline().addLast(new EchoServerHandler()); 
          } 
         }); 

       // Start the server. 
       ChannelFuture f = b.bind(PORT).sync(); 

       // Wait until the server socket is closed. 
       f.channel().closeFuture().sync(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } finally { 
       // Shut down all event loops to terminate all threads. 
       bossGroup.shutdownGracefully(); 
       workerGroup.shutdownGracefully(); 
      } 
     }).start(); 
    } 

    public void stop() throws InterruptedException { 
     workerGroup.shutdownGracefully(); 
     bossGroup.shutdownGracefully(); 
    } 
} 

Odpowiedz

9

Jednym ze sposobów jest, aby coś takiego:

// once having an event in your handler (EchoServerHandler) 
// Close the current channel 
ctx.channel().close(); 
// Then close the parent channel (the one attached to the bind) 
ctx.channel().parent().close(); 

Robi w ten sposób zakończy się, co następuje:

// Wait until the server socket is closed. Thread gets blocked. 
f.channel().closeFuture().sync(); 

Nie potrzeba dodatkowego wątku na głównej części. Teraz pytanie brzmi: jakiego rodzaju wydarzenie? To zależy od ciebie ... Może to być komunikat w programie obsługi echa jako "shutdown", który zostanie przyjęty jako kolejność wyłączenia, a nie tylko "quit", który zmieni się w zamykanie tylko kanału klienta. Może być czymś innym ...

Jeśli nie poradzisz sobie z wyłączaniem z kanału podrzędnego (tak przez program obsługi), ale poprzez inny proces (na przykład szukasz pliku zatrzymania istniejącego), potrzebujesz dodatkowego wątku, który będzie czekać na to zdarzenie, a następnie bezpośrednio utworzy channel.close(), gdzie kanał będzie nadrzędny (z f.channel()) na przykład ...

Istnieje wiele innych rozwiązań.