Всегда не удалось закрыть канал (нетто) со стороны сервера, когда клиент был физически убит - PullRequest
2 голосов
/ 14 февраля 2020

Это веб-приложение на основе netty. Однако, когда клиент физически убит без отправки CloseWebSocketFrame, сервер должен знать, что канал был закрыт, и выполнить некоторую работу по очистке. IdleStateHandler используется для контроля того, является ли канал свободным.

Вот конвейер обработчика канала.

public void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline();
    SSLEngine sslEngine = new SSLServiceBase().getSSLContext().createSSLEngine();
    sslEngine.setUseClientMode(false);
    sslEngine.setNeedClientAuth(true);
    ... // business process
    pipeline.addLast(new IdleStateHandler(30, 10, 0, TimeUnit.SECONDS));
    pipeline.addLast(new HeartbeatHandler());
}

Это userEventTriggered метод HeartbeatHandler, который используется для Выполните некоторую работу по очистке, когда канал ненормально закрыт от клиента.

public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    if (evt instanceof IdleStateEvent) {
        IdleStateEvent event = (IdleStateEvent) evt;
        if (IdleState.WRITER_IDLE.equals(event.state())) {
            ctx.writeAndFlush(new PingWebSocketFrame()).addListener(future -> {
                if (!future.isSuccess()) {
                    ChannelFuture closeFuture = ctx.channel().close();
                    if (closeFuture.isSuccess()) {
                        System.out.println("ping faild, channel close successfully");
                    } else {
                        System.out.println("ping failed, channel close failed");
                    }
                } else {
                    System.out.println("Ping succeed, keep the channel.");
                }
            });
        }
    } else {
        super.userEventTriggered(ctx, evt);
    }
}

На самом деле, я постоянно получаю 'close failed', и канал все еще жив с точки зрения сервера. Кто-нибудь может дать мне знать, почему канал не может быть закрыт или как его закрыть? Большое спасибо.

1 Ответ

1 голос
/ 14 февраля 2020

Я подозреваю, что закрытие еще не было сделано (помните, что это асинхронная c операция). Измените код на:

public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    if (evt instanceof IdleStateEvent) {
        IdleStateEvent event = (IdleStateEvent) evt;
        if (IdleState.WRITER_IDLE.equals(event.state())) {
            ctx.writeAndFlush(new PingWebSocketFrame()).addListener(future -> { 
                if (!future.isSuccess()) {
                    ctx.close().addListener(closeFuture -> {
                        If (closeFuture.isSuccess()) {
                            System.out.println("ping faild, channel close successfully");
                        } else {
                            System.out.println("ping failed, channel close failed");
                            // TODO: You may also want to log the reason why the close operation failed. 
                            //       closeFuture.cause() will contain why.
                        }
                    });                    
                } else {
                    System.out.println("Ping succeed, keep the channel.");
                }
        });
    }
} else {
    super.userEventTriggered(ctx, evt);
}

}

...