场景描述
采用netty时进行udp的连接,代码如下,初始连接正常,当网络进行重连时就开始报错:is not a @Sharable handler
public boolean connect(){
String host = utils.getPropStr("wincc-ip", "47.93.26.231");
int port = Integer.valueOf(utils.getPropStr("wincc-port", "13731"));
closeClient();
if(bootstrap==null) {
bootstrap = getBootStrap();
}
channelFuture = bootstrap.connect(host, port);
channelFuture.syncUninterruptibly();
if(channelFuture!=null && channelFuture.isSuccess()){
channel = channelFuture.channel();
protocol.mChannel = channelFuture.channel();
return true;
}else{
return false;
}
}
问题分析
分析链接:https://blog.youkuaiyun.com/haoziwlh/article/details/77684938
1.在写一个netty客户端时,对应的handler没有增加sharable注解,
2.当执行重连的逻辑时,此时会收到一个莫名其妙的错误java.nio.channels.ClosedChannelException
3.客户端每次connect都会重新建立一个channel。因为ClientHandler没有使用sharable注解
4.对于一个非sharable注解的handler,在第一次connect的时候isSharable()方法返回false,但是h.added是返回false的,可以通过
5.但当第二次被加入时,就出问题了isSharable()方法还是返回false,h.added也是true了,所以会抛出ChannelPipelineException
6.ChannelInitializer对应的channelRegistered方法捕捉到此异常后,没有执行success = true,导致ctx.close()方法执行
7.进而在connect的时候,ensureOpen方法将promise设置为CLOSED_CHANNEL_EXCEPTION,返回了,导致连接失败
@Sharable的真实含义
一.当netty尝试往多个channel的pipeline中添加同一个ChannelHandlerAdapter实例时,
会判断该实例类是否添加了@Sharable,没有则抛出异常
.. is not a @Sharable handler, so can't be added or removed multiple times
1.如果你添加的不是单例Handler,你加不加@Sharable没有任何区别
2.如果你添加的是单例Handler,只要它会被添加到多个channel的pipeline,那就必须加上@Sharable
二.网上有些资料说netty会将注解了@Sharable的Handler单例化,实在误导人。
1.channelHandler是不是单例跟netty没有任何关系
2.netty只会在你尝试用单例ChannelHandler时加上第1条说明的限制
3.这个限制意思很明确,多个channel公用单例ChannelHandler,那它就必须是线程安全的
4.@Sharable就是用于告诉netty,我这个Handler是线程安全的,可以被多个channel安全的share
5.假如你搞了个线程不安全的类,你对它用上了单例,还加个@Sharable,这时候netty拿你也没办法,
处理方法
方法:在ServerChannel类上添加@ChannelHandler.Sharable注解就可以了
@ChannelHandler.Sharable
public class UdpClientHandler extends SimpleChannelInboundHandler<Object> {
、、、
}
//这个注解适用于标注一个channel handler可以被多个channel安全地共享。
1.重新new一个channel 等待客户端的连接
2.对于对应使用的服务器的channelHandler类可以添加注解@ChannelHandler.Sharable
这个注解就是让这个handler可以被多个channel共享
当客户端重连时可以重新连接上服务端并且正常的发送数据。
补充说明
实际方案应该有多种
方案一:对应使用的服务器的channelHandler类可以添加注解@ChannelHandler.Sharable
该方案验证可行
方案二:重新new一个channel 等待客户端的连接
实际使用中出现通道冲突问题,由于时间原因未进一步验证
参考连接:
https://blog.youkuaiyun.com/haoziwlh/article/details/77684938
https://blog.youkuaiyun.com/wb_snail/article/details/106263470
https://blog.youkuaiyun.com/qq_28198181/article/details/82669656