简体   繁体   English

以编程方式关闭网络

[英]Shutdown netty programmatically

I'm using netty 4.0.24.Final.我正在使用 netty 4.0.24.Final。

I need to start/stop netty server programmatically.我需要以编程方式启动/停止 netty 服务器。
On starting the server, the thread gets blocked at在启动服务器时,线程被阻塞

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

Please help with some hints how to do it correctly.请帮助一些提示如何正确地做到这一点。 Below is the EchoServer that is called by the Main class.下面是 Main 类调用的 EchoServer。 Thanks.谢谢。

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: I changed the EchoServer class in the following way.更新:我通过以下方式更改了 EchoServer 类。 The idea is to start the server in a new thread and preserve the links to the EventLoopGroups.这个想法是在一个新线程中启动服务器并保留到 EventLoopGroups 的链接。 Is this the right way?这是正确的方法吗?

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

One way is to make something like:一种方法是制作类似的东西:

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

Doing this way will end up the following:这样做会导致以下结果:

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

No need for an extra thread on main part.主要部分不需要额外的线程。 Now the question is: what kind of event?现在的问题是:什么样的事件? It's up to you... Might be a message in the echo handler as "shutdown" that will be taken as an order of shutdown and not only "quit" which will turn as closing only the client channel.这取决于你......可能是回声处理程序中的一条消息“关闭”,将被视为关闭命令,而不仅仅是“退出”,后者将仅关闭客户端通道。 Might be something else...可能是别的东西...

If you do not handle the shutdown from a child channel (so through your handler) but through another process (for instance looking for a stop file existing), then you need an extra thread that will wait for this event and then directly make a channel.close() where channel will be the parent one (from f.channel() ) for instance...如果您不处理子频道的关闭(因此通过您的处理程序)而是通过另一个进程(例如寻找存在的停止文件),那么您需要一个额外的线程来等待此事件,然后直接创建一个channel.close()其中 channel 将是父级(来自f.channel() )例如......

Many other solutions exist.存在许多其他解决方案。

I was following official tutorials and encountered the same problem.我正在关注官方教程并遇到了同样的问题。 The tutorials have the same pattern:这些教程具有相同的模式:

f.channel().closeFuture().sync();
...
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();

That is, the channel is being closed before the groups shutdown.也就是说,通道在组关闭之前被关闭。 I changed the order to this:我把顺序改成这样:

        bossGroup.shutdownGracefully().sync();
        workerGroup.shutdownGracefully().sync();
        f.channel().closeFuture().sync();

And it worked.它奏效了。 This results to a rough modified example of a server which doesn't lock:这导致了一个不锁定的服务器的粗略修改示例:

class Server
{
    private ChannelFuture future;
    private NioEventLoopGroup masterGroup;
    private NioEventLoopGroup workerGroup;
    Server(int networkPort)
    {
        masterGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup();
        try
        {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(masterGroup, workerGroup);
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.option(ChannelOption.SO_BACKLOG,128);
            serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE,true);
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>()
            {
                @Override
                protected void initChannel(SocketChannel ch)
                {
                    ch.pipeline().addLast(new InboundHandler());
                }
            }).validate();
            future = serverBootstrap.bind(networkPort).sync();
            System.out.println("Started server on "+networkPort);

        }
        catch (Exception e)
        {
            e.printStackTrace();
            shutdown();
        }
    }

    void shutdown()
    {

        System.out.println("Stopping server");
        try
        {
            masterGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
            future.channel().closeFuture().sync();
            System.out.println("Server stopped");
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}

I just shut down the eventloopgroups我只是关闭了 eventloopgroups

 bossGroup.shutdownGracefully().sync();
 workerGroup.shutdownGracefully().sync();

and it works great because when I send request to my proxy server with retrofit it says that "fails to connect".它工作得很好,因为当我通过改造向我的代理服务器发送请求时,它说“无法连接”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM