java 以编程方式关闭网络
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28032092/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Shutdown netty programmatically
提问by fh76
I'm using netty 4.0.24.Final.
我正在使用 netty 4.0.24.Final。
I need to start/stop netty server programmatically.
On starting the server, the thread gets blocked at
我需要以编程方式启动/停止 netty 服务器。
在启动服务器时,线程被阻塞
f.channel().closeFuture().sync()
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. Thanks.
请帮助一些提示如何正确地做到这一点。下面是 Main 类调用的 EchoServer。谢谢。
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. The idea is to start the server in a new thread and preserve the links to the EventLoopGroups. Is this the right way?
更新:我通过以下方式更改了 EchoServer 类。这个想法是在一个新线程中启动服务器并保留到 EventLoopGroups 的链接。这是正确的方法吗?
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();
}
}
采纳答案by Frederic Brégier
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()
where例如,频道将是父频道(来自f.channel()
)...
Many other solutions exist.
存在许多其他解决方案。
回答by Alexiy
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();
}
}
}