上个月我的通信中心出现了,可以入库mysql5.7,但是不能推送给客户第三方API的情况,我就决定把通信中心一分为三,一个通信中心专门只接收然后转发信息给另外两个通信中心,
另外两个通信中心是这样安排的,一个专门解析国家水文协议及入库操作,另一个通信中心解析水文协议完后就推送给第三方API。说明一下我的程序是基于netty通信框架的。
然后就出现异常:io.netty.util.IllegalReferenceCountException: refCnt: 0
经过网络查询知道原因是:
这是因为Netty引用计数器的原因,自从Netty 4开始,对象的生命周期由它们的引用计数(reference counts)管理,而不是由垃圾收集器(garbage collector)管理了。ByteBuf是最值得注意的,它使用了引用计数来改进分配内存和释放内存的性能。
在我们创建ByteBuf对象后,它的引用计数是1,当你释放(release)引用计数对象时,它的引用计数减1,如果引用计数为0,这个引用计数对象会被释放(deallocate),并返回对象池。
主要原因就是我第一个专门中转的通信中心收到RTU设备的信息后要转发给两个通信中心,第一次转发的时候是没有问题的,这个时候ctx.write 等一系列方法调用了ByteBuf的release方法,将其引用计数减为0了,当第二次转发的时候就报异常了。
解决的方法:
.retain();// 我们可以调用ByteBuf.retain()将引用计数加1
.duplicate();//复制当前对象,复制后的对象与前对象共享缓冲区,且维护自己的独立索引
接下就是一个通信中心推送(转发)另外两个通信中心的思路:
由于业务就是要处理RTU设备发送过来的信息再加上推送给第三方API,如果设备没有连接上来,三个通信中心也得自己互连互通。
思路如下:
第一部分:自定义自己的包头不能和水文的7E7E一样就可以了。
第二部分:安排两个字节指示剩下报文的长度。
第三部分:两个字节水文协议报文长度。
第四部分:水文协议报文内容(如果第三部分长度大于零)。
第五部分:通信中心之间的心跳信息(如果第三部分长度等于零)。
经过排查发现我用的第三方推送程序挂一两天后就是不推送了,替换另的推送程序。经过一个月了,程序已经稳定。
原文地址:https://www.cnblogs.com/yebinghuai/p/12037906.html