工作中要能主動地關閉netty server端,下面的文章中的方法是好用的,記錄一下。
原文地址:https://blog.csdn.net/wk52525/article/details/87896075
1.主動關閉server
- 如下面的代碼所示,這里啟動server時將ServerChannel的實例保存至靜態屬性,然后暴露一個closeServer()方法,直接調用ServerChannel的close()方法,此線程則會從阻塞狀態恢復,向下執行,進入finally代碼塊,退出server並清理相關資源。
package com.huoli.mj.rpc.server; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class NettyServer { private static Logger logger = LoggerFactory.getLogger(NettyServer.class); private static Channel serverChannel; /** 關閉當前server */ public static void closeServer() { if (serverChannel != null) { logger.info("close server"); serverChannel.close(); serverChannel = null; } } /** 啟動server */ private void start(int port) throws Exception { // 通過獨立線程啟動server Thread nettyServer = new Thread(() -> { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) .childHandler(new DefaultServerChannelInitializer()).option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); // 綁定端口啟動成功 ChannelFuture channelFuture = b.bind(port).sync(); logger.info("start rpc server success with port:" + port); // 將ServerChannel保存下來 serverChannel = channelFuture.channel(); // 阻塞至channel關閉 serverChannel.closeFuture().sync(); } catch (Exception e) { logger.error("MJ netty server error", e); } finally { // 優雅關閉server線程及相關資源 workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } }); nettyServer.setName("netty-server-thread"); nettyServer.setDaemon(true); nettyServer.start(); } }
2.在ChannelHandler中關閉server
- 在某些場景下,會需要在特定事件回調時主動關閉server端。下面代碼展示了在監聽到異常拋出事件時主動關閉server的操作。
- 以下面代碼為例:ChannelHandler的事件回調方法中,ctx.close() 或 ctx.channel().close()只能關閉與某個客戶端連接的channel,而ctx.channel().parent()獲取到的是ServerChannel,所以調用ctx.channel().parent().close()才能關閉server,使server啟動線程從阻塞狀態恢復,從而在finally代碼塊中執行退出關閉操作。
package top.kylewang.netty.demo.second.server; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TestSocketServerHandler extends ChannelInboundHandlerAdapter { private static final Logger logger = LoggerFactory.getLogger(TestSocketServerHandler.class); /** 監聽異常 */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); // 關閉serverChannel ctx.channel().parent().close(); }