概要
一般而言, 个人极其建议在应用中添加业务心跳, 如果将应用连接的稳定性单单寄托在tcp keepalive, 当出现类似拔网线,CPU百分百时, 对端将无法及时感知.
当然这区分服务端和客户端, 两者策略不同, 具体场景具体对待.
正文开始, 先引入Nettyx的依赖
请从maven中央仓获取{lastest.version},最新版本号
<dependency>
<groupId>io.github.fbbzl</groupId>
<artifactId>nettyx</artifactId>
<version>{lastest.version}</version>
</dependency>
IdledHeartBeater
Nettyx提供了abstract IdledHeartBeater, 为了不占用带宽, 它只会在闲置的时候进行心跳, 既然是在闲置时心跳.
那么很自然的有三个实现类 :
ReadIdleHeartBeater: 读闲置时心跳, 只会在一定时间内没有read到数据才会开始心跳
WriteIdleHeartBeater: 写闲置时心跳, 只会在一定时间内没有write数据才会开始心跳
AllIdleHeartBeater: 读写闲置时心跳, 整和版, 只会在一定时间内既没有read也没有write时开始心跳
使用很简单
private ChannelInitializer<NioSocketChannel> channelInitializer(SocketAddress address) {
return new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel channel) {
channel.pipeline()
// ReadIdleHeartBeater有自己的读闲置计数, 和pipeline中其他的读闲置handler不冲突
// 例如,如果同时设置了inboundadvice 或者idlestatehandler
// 他们的读闲置时间设置并不会影响到ReadIdleHeartBeater的闲置时间,
// ReadIdleHeartBeater的读闲置只会用来发送心跳消息, 也不会在pipeline中传播
.addLast(new ReadIdleHeartBeater(2, ctx -> ctx.write("heart beat msg")))
// in out
// ▼ ▲ remove start and end flag
.addLast(new StartEndFlagFrameCodec(1024 * 1024, false,
Unpooled.wrappedBuffer(new byte[]{(byte) 0x7e})))
.addLast(new EscapeCodec(EscapeMap.mapHex("7e", "7d5e")))
.addLast(new UserCodec())
// ▼ ▲ deal control character and recover application data
.addLast(new LoggerHandler.InboundLogger(log, LoggerHandler.Sl4jLevel.ERROR);
}
};
}
至此我们完成了 闲置发送心跳 的功能
???什么你跟我说常规的心跳器???如果你并不想在闲置时发送心跳, 而是应用启动即全程开始心跳, 那么我懒得封装, 一个定时任务就足矣可以搞定了, 当然了, 要注意管理好这个定时器的生命周期,以及客户端/服务端实现之间的差别