netty自定义消息实现心跳检测与重连

本文介绍了如何在Netty中自定义心跳检测和重连机制,特别是在客户端。利用IdleStateHandler来检测无数据交换的状态,并在超时后触发相应操作。详细代码包括自定义协议的解码器、编码器、服务端和客户端的实现,以及客户端的重连检测逻辑。通过运行示例,展示了服务端和客户端的交互,当服务端关闭时,客户端能进行有效的日志记录并尝试重连。
摘要由CSDN通过智能技术生成

netty的心跳发送的重连,主要在client端。前面有关于自定义协议的demo:https://blog.csdn.net/zc_ad/article/details/83829620

其实客户端心跳发送用到的是IdleStateHandler,详细看代码你就会明白为什么。

 //处理空闲状态事件的处理器
pipeline.addLast(new IdleStateHandler(6,7,8, TimeUnit.SECONDS));

在IdleStateHandler中前三个参数分别是:

1.当在6秒内收到消息,触发IdleStateEvent事件。

2.当在7秒内没有发送消息,触发IdleStateEvent事件。

3.当在8内没有接收到数据且在8秒内没有发送数据,触发IdleStateEvent事件。

下面是实现的代码,代码量有点多....:

 

常量数据:

/**
 * Created by XiChuan on 2018-11-07.
 */
public class Constant {

    public static final int HEAD = 0x76;

    public static final String TYPE_PING = "PING";

    public static final String TYPE_MESSAGE = "MESSAGE";
}

自定义协议:

/**
 * Created by XiChuan on 2018-11-07.
 */

import java.util.Arrays;

/**
 * <pre>
 * 自己定义的协议
 *  数据包格式
 * +——----——+——-----——+——----——+
 * |协议开始标志|  消息类型长度  |  消息类型 |    数据长度   |   数据    |
 * +——----——+——-----——+——----——+
 * 1.协议开始标志head_data,为int类型的数据,16进制表示为0X76
 * 2.要传的协议类型长度(String的byte[]长度)
 * 3.要传的协议类型(String)
 * 4.传输数据的长度contentLength,int类型
 * 5.要传输的数据
 * </pre>
 */
public class MessageProtocol {
    /**
     * 消息的开头的信息标志
     */
    private int headData = Constant.HEAD;

    /**
     * 消息类型长度
     */
    private int typeLength;

    /**
     * 消息类型
     */
    private String type;

    /**
     * 消息的长度
     */
    private int contentLength;
    /**
     * 消息的内容
     */
    private byte[] content;

    /**
     * 用于初始化,SmartCarProtocol
     *
     * @param contentLength
     *            协议里面,消息数据的长度
     * @param content
     *            协议里面,消息的数据
     */
    public MessageProtocol(int typeLength,String type,int contentLength, byte[] content) {
        this.typeLength = typeLength;
        this.type = type;
        this.contentLength = contentLength;
        this.content = content;
    }

    public int getHeadData() {
        return headData;
    }

    public void setHeadData(int headData) {
        this.headData = headData;
    }

    public int getTypeLength() {
        return typeLength;
    }

    public void setTypeLength(int typeLength) {
        this.typeLength = typeLength;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public int getContentLength() {
        return contentLength;
    }

    public void setContentLength(int contentLength) {
        this.contentLength = contentLength;
    }

    public byte[] getContent() {
        return content;
    }

    public void setContent(byte[] content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return "MessageProtocol " +
                "[head_data=" + headData
                +", typeLength="+typeLength
                +", type="+type
                + ", contentLength=" + contentLength
                + ", content=" + Arrays.toString(content) + "]";
    }
}

定义解码器:

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * Created by XiChuan on 2018-11-06.
 */


public class MessageProtocolDecoder extends ByteToMessageDecoder {

    /**
     * <pre>
     * 协议开始的标准head_data,int类型,占据4个字节.
     * 表示数据的长度contentLength,int类型,占据4个字节.
     * </pre>
     */
    public final int BASE_LENGTH = 4 + 4;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf buffer,
                          List<Object> out) throws Exception {
        // 可读长度必须大于基本长度
        //System.out.println("buff的可读长度是:"+buffer.readableBytes());
        if (buffer.readableBytes() >= BASE_LENGTH) {
            // 防止socket字节流攻击
            // 防止,客户端传来的数据过大
            // 因为,太大的数据,是不合理的
            if (buffer.readableBytes() > 2048) {
                buffer.skipBytes(buffer.readableBytes());
            }
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Netty 中,实现心跳检测可以使用 IdleStateHandler 类。这个类是一个 ChannelHandler,可以在一段时间内检测 Channel 是否有读或写事件发生,如果超时没有发生事件,就会触发一个 IdleStateEvent 事件。我们可以在 ChannelPipeline 中添加 IdleStateHandler,并在 ChannelInboundHandler 中处理 IdleStateEvent 事件。 以下是一个简单的示例代码: ```java public class HeartbeatServerInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); // 添加 IdleStateHandler,10 秒钟没有读事件,20 秒钟没有写事件,30 秒钟没有读写事件就会触发 IdleStateEvent 事件 pipeline.addLast(new IdleStateHandler(10, 20, 30, TimeUnit.SECONDS)); // 添加自定义的处理器,处理 IdleStateEvent 事件 pipeline.addLast(new HeartbeatServerHandler()); } } public class HeartbeatServerHandler extends ChannelInboundHandlerAdapter { @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt instanceof IdleStateEvent) { IdleStateEvent e = (IdleStateEvent) evt; if (e.state() == IdleState.READER_IDLE) { // 10 秒钟没有读事件,可以认为客户端已经断开连接 ctx.close(); } else if (e.state() == IdleState.WRITER_IDLE) { // 20 秒钟没有写事件,发送心跳包 ctx.writeAndFlush(new HeartbeatMessage()); } else if (e.state() == IdleState.ALL_IDLE) { // 30 秒钟没有读写事件,可以认为客户端已经断开连接 ctx.close(); } } } } ``` 在上面的代码中,我们首先添加了一个 IdleStateHandler,指定了读超时时间、写超时时间和读写超时时间,然后添加了一个自定义的 ChannelInboundHandlerAdapter,重写了 userEventTriggered 方法,处理 IdleStateEvent 事件。在方法中,我们根据不同的 IdleState 处理不同的事件,例如读超时就关闭连接,写超时就发送心跳包。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值