banner
RustyNail

RustyNail

coder. 【blog】https://rustynail.me 【nostr】wss://ts.relays.world/ wss://relays.world/nostr

Implementing Heartbeat Mechanism Using IdleStateHandler

Introduction to IdleStateHandler#

IdleStateHandler is essentially a channel handler, which means it can be added to the pipeline.

The purpose of IdleStateHandler is to trigger an IdleStateEvent in certain situations.

Certain situations include:

  • No reading within a certain period of time
  • No writing within a certain period of time
  • No reading or writing within a certain period of time

After triggering an IdleStateEvent, it can be received by downstream handlers.

For example, if there is no reading operation for 10 seconds, a READER_IDLE event is triggered.

ch.pipeline()
    .addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS))
    .addLast(new HeartTrigger())
    }
});

The downstream HeartTrigger can receive this event.

public class HeartTrigger extends ChannelInboundHandlerAdapter {
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            // do something
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
}

Heartbeat#

The heartbeat model is simple. After the client and server establish a connection, the IdleStateHandler is used to listen for write operations. If there is no write operation within a certain period of time, a heartbeat packet is sent actively to trigger a write operation.

The client's write operation corresponds to the server's read operation. In other words, the client's heartbeat packet may cause the server to perform a read operation.

The server listens for read operations on the channel. If there is no read operation within a timeout period, the channel (connection) will be closed.

The server's read listening interval should be slightly longer than the client's write listening interval to avoid closing the channel due to slight delays.

Relevant Code#

The heartbeat packet is a custom data structure, and the possibility of partial packets or packet sticking should be considered.

Client sends heartbeat packet

@Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            if (((IdleStateEvent) evt).state() == IdleState.WRITER_IDLE) {
                logger.info("Send a heartbeat packet to tell the server that I'm still alive..");
                ctx.writeAndFlush(new TransData.Builder()
                        .type(TransData.TYPE_HT)
                        .build());
            }
        }
    }

Server closes the channel if it hasn't received anything from the client for a long time.

@Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            if (((IdleStateEvent) evt).state() == IdleState.READER_IDLE) {
                logger.info("No heartbeat from the client for too long, disconnecting");
                ctx.close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.