心跳是为了保证客户端和服务端的通信可用。因为各种原因客户端和服务端不能及时响应和接收信息。比如网络断开,停电 或者是客户端/服务端 高负载。
所以每隔一段时间 客户端发送心跳包到客户端 服务端做出心跳的响应;
1.如果客户端在指定时间没有向服务端发送心跳包。则表示客户端的通信出现了问题。
2.如果客户端发送心跳包到服务端没有收到响应 则表示服务端的通信出现了问题。
netty提供IdleStateHandle 在监听距离上一次写的时间和距离上一次读的时间 如果超时则调用
源码:
public class IdleStateHandler extendsChannelDuplexHandler
@Overridepublic void channelActive(ChannelHandlerContext ctx) throwsException {//This method will be invoked only if this handler was added//before channelActive() event is fired. If a user adds this handler//after the channelActive() event, initialize() will be called by beforeAdd().
initialize(ctx);super.channelActive(ctx);
}
}
private voidinitialize(ChannelHandlerContext ctx) {//Avoid the case where destroy() is called before scheduling timeouts.//See:https://github.com/netty/netty/issues/143
switch(state) {case 1:case 2:return;
}
state= 1;
initOutputChanged(ctx);
lastReadTime= lastWriteTime =ticksInNanos();if (readerIdleTimeNanos > 0) {
readerIdleTimeout= schedule(ctx, newReaderIdleTimeoutTask(ctx),//监听read的task
readerIdleTimeNanos, TimeUnit.NANOSECONDS);
}if (writerIdleTimeNanos > 0) {
writerIdleTimeout= schedule(ctx, newWriterIdleTimeoutTask(ctx),//监听写的task
writerIdleTimeNanos, TimeUnit.NANOSECONDS);
}if (allIdleTimeNanos > 0) {
allIdleTimeout= schedule(ctx, newAllIdleTimeoutTask(ctx),//监听读写的task
allIdleTimeNanos, TimeUnit.NANOSECONDS);
}
}
private final class ReaderIdleTimeoutTask extendsAbstractIdleTask {
ReaderIdleTimeoutTask(ChannelHandlerContext ctx) {super(ctx);
}
@Overrideprotected voidrun(ChannelHandlerContext ctx) {long nextDelay =readerIdleTimeNanos;if (!reading) {
nextDelay-= ticksInNanos() -lastReadTime;
}if (nextDelay <= 0) {//Reader is idle - set a new timeout and notify the callback.
readerIdleTimeout = schedule(ctx, this, readerIdleTimeNanos, TimeUnit.NANOSECONDS);boolean first =firstReaderIdleEvent;
firstReaderIdleEvent= false;try{
IdleStateEvent event=newIdleStateEvent(IdleState.READER_IDLE, first);
channelIdle(ctx, event);
}catch(Throwable t) {
ctx.fireExceptionCaught(t);
}
}else{//Read occurred before the timeout - set a new timeout with shorter delay.
readerIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);
}
}
}private final class WriterIdleTimeoutTask extendsAbstractIdleTask {
WriterIdleTimeoutTask(ChannelHandlerContext ctx) {super(ctx);
}
@Overrideprotected voidrun(ChannelHandlerContext ctx) {long lastWriteTime = IdleStateHandler.this.lastWriteTime;long nextDelay = writerIdleTimeNanos - (ticksInNanos() -lastWriteTime);if (nextDelay <= 0) {//Writer is idle - set a new timeout and notify the callback.
writerIdleTimeout = schedule(ctx, this, writerIdleTimeNanos, TimeUnit.NANOSECONDS);boolean first =firstWriterIdleEvent;
firstWriterIdleEvent= false;try{if(hasOutputChanged(ctx, first)) {return;
}
IdleStateEvent event=newIdleStateEvent(IdleState.WRITER_IDLE, first);
channelIdle(ctx, event);
}catch(Throwable t) {
ctx.fireExceptionCaught(t);
}
}else{//Write occurred before the timeout - set a new timeout with shorter delay.
writerIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);
}
}
}private final class AllIdleTimeoutTask extendsAbstractIdleTask {
AllIdleTimeoutTask(ChannelHandlerContext ctx) {super(ctx);
}
@Overrideprotected voidrun(ChannelHandlerContext ctx) {long nextDelay =allIdleTimeNanos;if (!reading) {
nextDelay-= ticksInNanos() -Math.max(lastReadTime, lastWriteTime);
}if (nextDelay <= 0) {//Both reader and writer are idle - set a new timeout and//notify the callback.
allIdleTimeout = schedule(ctx, this, allIdleTimeNanos, TimeUnit.NANOSECONDS);boolean first =firstAllIdleEvent;
firstAllIdleEvent= false;try{if(hasOutputChanged(ctx, first)) {return;
}
IdleStateEvent event=newIdleStateEvent(IdleState.ALL_IDLE, first);
channelIdle(ctx, event);
}catch(Throwable t) {
ctx.fireExceptionCaught(t);
}
}else{//Either read or write occurred before the timeout - set a new//timeout with shorter delay.
allIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);
}
}
}
三个内部类是IdleSateHandle的内部类 可以看到内部是通过另起一个线程进行监听上一次对应事件的触发 如果超时则调用对应的事件
基于三的代码进行修改
首先是MessageHead消息头增加消息类型