我这边第一次连接netty可以,但是关闭netty连接以后,再次使用连接就会报这个错,其实很简单的问题,但是一下子蒙住了,搞了半天,后来发现是全局变量的问题,
我把下面这两行代码放入了全局变量里,重启系统第一次连接没问题,关闭连接第二次开启连接就出现报错 Force-closing a channel whose registration task was not accepted by an event loop 连接不上。
EventLoopGroup parentGroup = new NioEventLoopGroup();
//负责网络的读写
EventLoopGroup childGroup = new NioEventLoopGroup();
因为我还得需要通过接口关闭连接,针对上面问题我是这样改的
定义一个安全线程的hashmap用来存储EventLoopGroup 对象,在关闭资源方法里通过map取出来进行关闭,就不会出现这个问题了
@Component
public class NettyServer {
private static Logger logger = LoggerFactory.getLogger(NettyServer.class);
private ConcurrentHashMap mapEventLoopGroup = new ConcurrentHashMap();
private Channel channel;
// 开启连接
public ChannelFuture bing(InetSocketAddress address) {
// 配置服务端NIO线程组-负责接收客户端的连接
EventLoopGroup parentGroup = new NioEventLoopGroup();
//负责网络的读写
EventLoopGroup childGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
ChannelFuture channelFuture = null;
System.out.println("进入bind方法");
try {
// 添加boss和worker组
b.group(parentGroup, childGroup)
// 非阻塞模式
.channel(NioServerSocketChannel.class)
// 设置TCP的缓冲区
.option(ChannelOption.SO_BACKLOG, 128)
// 增加接收缓冲区
.option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(4096))
// childHandler 去绑定具体的事件处理器
.childHandler(new ChannelInit());
// 绑定端口
channelFuture = b.bind(address).syncUninterruptibly();
System.out.println("绑定端口");
System.out.println(channelFuture);
channel = channelFuture.channel();
System.out.println(channel);
mapEventLoopGroup.put("parent", parentGroup);
mapEventLoopGroup.put("child", childGroup);
} catch (Exception e) {
// 优雅退出,释放线程池资源
System.out.println("进入catch方法");
e.printStackTrace();
parentGroup.shutdownGracefully();
childGroup.shutdownGracefully();
} finally {
if (null != channelFuture && channelFuture.isSuccess()) {
logger.info("netty服务启动完成!");
} else {
logger.error("netty服务启动失败!");
}
}
return channelFuture;
}
// 关闭连接
public boolean destroy() {
try {
if (null == channel) {
return false;
} else {
channel.close();
channel = null;
System.out.println("关闭channel");
}
if (mapEventLoopGroup.containsKey("parent")) {
EventLoopGroup parentGroup = (EventLoopGroup) mapEventLoopGroup.get("parent");
parentGroup.shutdownGracefully();
System.out.println("关闭parent");
mapEventLoopGroup.remove("parent");
}
if (mapEventLoopGroup.containsKey("child")) {
EventLoopGroup child = (EventLoopGroup) mapEventLoopGroup.get("child");
child.shutdownGracefully();
System.out.println("关闭child");
mapEventLoopGroup.remove("child");
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public Channel getChannel() {
return channel;
}
/*
* @Author df
* @Description 发送消息
* @Date 15:28 2021/1/14
**/
public AjaxResult sendMessage(byte[] byteData, String orderNo) {
System.out.println("进入发送message方法(),命令号是:" + orderNo);
System.out.println(ServerHandler.ctxMaps.size());
try {
// 指定不同的连接请求发送命令
for (Map<String, ChannelHandlerContext> ctxMap : ServerHandler.ctxMaps) {
if (ctxMap.containsKey(orderNo)) {
ChannelHandlerContext ctx = ctxMap.get(orderNo);
if (ctx == null) {
return AjaxResult.error("请确保打开TCP连接操作!");
}
// netty需要转换ByteBuf才可使用
ByteBuf bytebuf = Unpooled.buffer();
bytebuf.writeBytes(byteData);
ServerHandler.isAccess = true;
ctx.writeAndFlush(bytebuf);
String ip = IpCabinetBind.findOrderNoByIp(orderNo);
String msg = "给Ip为:" + ip + "发送了命令号是" + orderNo + "指令";
System.out.println(msg);
Session session = WebSocketServer.sessionPools.get("android");
if (session != null) {
boolean isSucc = WebSocketServer.sendMessage(session, msg);
}
}
}
} catch (Exception e) {
e.printStackTrace();
ServerHandler.isAccess = false;
return AjaxResult.error("服务器报错!发送指令失败!");
}
return null;
}
}