5

接続が開いているNettyサーバーをシャットダウンしようとしていますが、ハングします。これが私がすることです。

  • あるマシンでサーバーを起動し、別のマシンでクライアントを起動します。
  • クライアントからサーバーにメッセージを送信し、応答を受け取ります。
  • Ctrl-Cを使用してサーバーをシャットダウンします

ChannelGroupを閉じ、ServerBootstrapでreleaseExternalResourcesを呼び出すシャットダウンフックをサーバーに登録しました(または、実際には、それを実行するprotobuf-pro-duplexライブラリのDuplexTcpServerBootstrapを使用しています)。とにかく、シャットダウンフックはシャットダウン時に適切に呼び出されますが、戻ることはありません。何が起こっているのかをスレッドダンプすると、2つの興味深いスタックが表示されます。

   java.lang.Thread.State: TIMED_WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000006b0890950> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2082)
    at java.util.concurrent.ThreadPoolExecutor.awaitTermination(ThreadPoolExecutor.java:1433)
    at org.jboss.netty.util.internal.ExecutorUtil.terminate(ExecutorUtil.java:103)
    at org.jboss.netty.channel.socket.nio.AbstractNioWorkerPool.releaseExternalResources(AbstractNioWorkerPool.java:80)
    at org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory.releaseExternalResources(NioServerSocketChannelFactory.java:162)
    at org.jboss.netty.bootstrap.Bootstrap.releaseExternalResources(Bootstrap.java:319)
    at com.googlecode.protobuf.pro.duplex.server.DuplexTcpServerBootstrap.releaseExternalResources(DuplexTcpServerBootstrap.java:132)
    at com.xxx.yyy.node.NodeServer$2.run(NodeServer.java:104)
    at java.lang.Thread.run(Thread.java:722)

したがって、これは決して戻らないシャットダウンフックスレッドです。以下は、チャネルで待機しているように見える別のスレッドです。

   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.EPollArrayWrapper.interrupt(Native Method)
    at sun.nio.ch.EPollArrayWrapper.interrupt(EPollArrayWrapper.java:274)
    at sun.nio.ch.EPollSelectorImpl.wakeup(EPollSelectorImpl.java:193)
    - locked <0x00000006b0896660> (a java.lang.Object)
    at java.nio.channels.spi.AbstractSelector$1.interrupt(AbstractSelector.java:210)
    at java.nio.channels.spi.AbstractSelector.begin(AbstractSelector.java:216)
    at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:80)
    at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:87)
    - locked <0x00000006b08964a8> (a sun.nio.ch.Util$2)
    - locked <0x00000006b0896498> (a java.util.Collections$UnmodifiableSet)
    - locked <0x00000006b0890d20> (a sun.nio.ch.EPollSelectorImpl)
    at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:98)
    at org.jboss.netty.channel.socket.nio.SelectorUtil.select(SelectorUtil.java:52)
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:208)
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:38)
    at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:102)
    at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)

Linux上のJava7.04でNetty3.4.6.Finalを使用しています。ありがとう!

Br、フランク。

4

3 に答える 3

4

裸のNettyクライアント/サーバーでも同じ「問題」がありました。

つまり、サーバー チャネルを閉じても、受け入れられたクライアント接続用に作成された開いているチャネルは閉じられません。サーバーでクライアントチャネルを明示的に追跡する必要があります。これは、チャネル グループと、このグループにクライアント チャネルを追加するハンドラを使用して実行できます。サーバーをシャットダウンするときは、1 つのサーバー チャネル (チャネル グループにも入れることができる) だけではなく、グループ内のすべてのチャネルをバッチのような方法で閉じる必要があります。

ユーザー ガイド (9. アプリケーションのシャットダウン): http://static.netty.io/3.5/guide/および ChannelGroup API ドキュメント (ChannelGroup によるシャットダウン プロセスの簡素化): http://static に優れたドキュメントがあります。 netty.io/3.5/api/org/jboss/netty/channel/group/ChannelGroup.html

于 2012-08-04T10:47:33.740 に答える
3

私は同じ問題を抱えていて、それを解決しました。すべてをEventLoopGroup同期的にシャットダウンしてから、ポートを閉じる必要があります。

完全にシャットダウンするには 4 ~ 5 秒かかる場合があります。

startここにコード例があります(テストするには、 とstopボタンを使用して簡単な GUI を作成する必要があると思います)。

public class ReusePortServer {
    private final int port;
    ChannelFuture f;
    EventLoopGroup group;
    EpollEventLoopGroup bossGroup;
    EpollEventLoopGroup workerGroup;


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

    public void start() throws Exception {

        group = new EpollEventLoopGroup();

        bossGroup = new EpollEventLoopGroup();
        workerGroup = new EpollEventLoopGroup();

        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup)
                .channel(EpollServerSocketChannel.class)
                .option(EpollChannelOption.SO_REUSEPORT, true)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new ReusePortHandler());
                    }
                });

        f = b.bind(port).sync();
        log(String.format("%s started and listen on %s", ReusePortServer.class.getName(), f.channel().localAddress()));
    }

    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 void stop() {
        System.out.println("ReusePortServer.stop");
        try {
            // shutdown EventLoopGroup
            bossGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
            f.channel().closeFuture().sync();   // close port

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

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

注:必要に応じて変更EpollEventLoopGroupできEventLoopGroupます。

于 2016-08-13T08:55:05.723 に答える
0

Netty サーバーのシャットダウン

  1. サーバー チャネルを閉じる
  2. シャットダウン ボスとワーカー エグゼキュータ
  3. サーバーのブートストラップ リソースを解放する

サンプルコード

ChannelFuture cf = serverChannel.close();
cf.awaitUninterruptibly();
bossExecutor.shutdown();
workerExecutor.shutdown();
thriftServer.releaseExternalResources();
于 2012-06-07T10:49:48.520 に答える