Netty自定义协议

简介: 先写一个Messsage类,解码的时候将要把ByteBuf解码为Message

首发于Enaium的个人博客


先写一个Messsage类,解码的时候将要把ByteBuf解码为Message

public class Message implements Serializable {
   
    private final String data;

    public Message(String data) {
   
        this.data = data;
    }

    @Override
    public String toString() {
   
        return "Message{" +
                "data='" + data + '\'' +
                '}';
    }
}

之后创建MessageCodec类,继承MessageToMessageCodec

入站为ByteBuf解码为Message,出站为Message编码为ByteBuf

重写编码的解码方法

public class MessageCodec extends MessageToMessageCodec<ByteBuf, Message> {
   
    @Override
    public void encode(ChannelHandlerContext channelHandlerContext, Message message, List<Object> list) throws Exception {
   
    }

    @Override
    public void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
   
    }
}

这里用四个字节表示内容的长度,最后是所有内容,这里使用JDK来序列化

public void encode(ChannelHandlerContext channelHandlerContext, Message message, List<Object> list) throws Exception {
   
    ByteBuf buffer = channelHandlerContext.alloc().buffer();
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
    objectOutputStream.writeObject(message);
    byte[] bytes = byteArrayOutputStream.toByteArray();
    buffer.writeInt(bytes.length);
    buffer.writeBytes(bytes);
    list.add(buffer);
}

怎么编码的就怎么解码,读取长度读取内容

public void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
   
    int length = byteBuf.readInt();
    byte[] bytes = new byte[length];
    byteBuf.readBytes(bytes);
    ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
    Message message = (Message) objectInputStream.readObject();
    System.out.println("message = " + message);
    list.add(message);
}

一个简单的协议就写好了,现在就来测试一下

使用EmbeddedChannel这个Channel来进行测试,处理器就添加一个日志处理器和刚才写好的编解码器

写入Message

EmbeddedChannel embeddedChannel = new EmbeddedChannel(new LoggingHandler(LogLevel.INFO), new MessageCodec());
embeddedChannel.writeOutbound(new Message("HELLO WORLD"));

运行一下试试

写入了92个字节的数据,长度为0x58转为10进制为88加上长度占的4个字节刚好92个字节

信息: [id: 0xembedded, L:embedded - R:embedded] WRITE: 92B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 00 00 58 ac ed 00 05 73 72 00 19 63 6e 2e 65 |...X....sr..cn.e|
|00000010| 6e 61 69 75 6d 2e 6d 65 73 73 61 67 65 2e 4d 65 |naium.message.Me|
|00000020| 73 73 61 67 65 95 ee d0 49 e2 3a be 6d 02 00 01 |ssage...I.:.m...|
|00000030| 4c 00 04 64 61 74 61 74 00 12 4c 6a 61 76 61 2f |L..datat..Ljava/|
|00000040| 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 78 70 74 00 |lang/String;xpt.|
|00000050| 0b 48 45 4c 4c 4f 20 57 4f 52 4c 44             |.HELLO WORLD    |
+--------+-------------------------------------------------+----------------+

接着测试解码,这里粗暴的使用了刚才的日志

embeddedChannel.writeInbound(Unpooled.wrappedBuffer(new byte[]{
   
        0x00, 0x00, 0x00, 0x58, (byte) 0xac, (byte) 0xed, 0x00, 0x05, 0x73, 0x72, 0x00, 0x19, 0x63, 0x6e, 0x2e, 0x65,
        0x6e, 0x61, 0x69, 0x75, 0x6d, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65,
        0x73, 0x73, 0x61, 0x67, 0x65, (byte) 0x95, (byte) 0xee, (byte) 0xd0, 0x49, (byte) 0xe2, 0x3a, (byte) 0xbe, 0x6d, 0x02, 0x00, 0x01,
        0x4c, 0x00, 0x04, 0x64, 0x61, 0x74, 0x61, 0x74, 0x00, 0x12, 0x4c, 0x6a, 0x61, 0x76, 0x61, 0x2f,
        0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3b, 0x78, 0x70, 0x74, 0x00,
        0x0b, 0x48, 0x45, 0x4c, 0x4c, 0x4f, 0x20, 0x57, 0x4f, 0x52, 0x4c, 0x44
}));

读取了92个字节,也成功解码

信息: [id: 0xembedded, L:embedded - R:embedded] READ: 92B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 00 00 58 ac ed 00 05 73 72 00 19 63 6e 2e 65 |...X....sr..cn.e|
|00000010| 6e 61 69 75 6d 2e 6d 65 73 73 61 67 65 2e 4d 65 |naium.message.Me|
|00000020| 73 73 61 67 65 95 ee d0 49 e2 3a be 6d 02 00 01 |ssage...I.:.m...|
|00000030| 4c 00 04 64 61 74 61 74 00 12 4c 6a 61 76 61 2f |L..datat..Ljava/|
|00000040| 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 78 70 74 00 |lang/String;xpt.|
|00000050| 0b 48 45 4c 4c 4f 20 57 4f 52 4c 44             |.HELLO WORLD    |
+--------+-------------------------------------------------+----------------+
message = Message{data='HELLO WORLD'}

一个简单的协议就写好了

视频

源码

目录
相关文章
|
7月前
|
Java Spring
Springboot整合Netty,自定义协议实现
以上就是在Spring Boot中整合Netty并实现自定义协议的基本步骤。你需要根据你的自定义协议的具体需求,来实现你的编码器、解码器和处理器。
285 0
|
7月前
|
编解码
Netty Review - 优化Netty通信:如何应对粘包和拆包挑战_自定义长度分包编解码码器
Netty Review - 优化Netty通信:如何应对粘包和拆包挑战_自定义长度分包编解码码器
112 0
|
7月前
|
存储 编解码 Java
Netty使用篇:自定义编解码器
Netty使用篇:自定义编解码器
|
7月前
|
编解码 JSON 网络协议
Netty使用篇:Http协议编解码
Netty使用篇:Http协议编解码
|
Nacos
Netty自定义消息协议的实现逻辑处理粘包拆包、心跳机制
Netty自定义消息协议的实现逻辑处理粘包拆包、心跳机制
175 0
|
数据安全/隐私保护
Netty实战(十四)WebSocket协议(二)
我们之前说过为了将 ChannelHandler 安装到 ChannelPipeline 中,需要扩展了ChannelInitializer,并实现 initChannel()方法
206 0
|
JSON 网络协议 算法
由浅入深Netty协议设计与解析
由浅入深Netty协议设计与解析
71 0
|
JSON 网络协议 算法
Netty之协议设计
Netty之协议设计
|
NoSQL Redis
使用netty按照Redis协议发消息完成set key value 命令
使用netty按照Redis协议发消息完成set key value 命令
92 0
|
存储 缓存 NoSQL
跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)
本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯一ID、红包、消息同步等功能,并且还支持集群部署。
13531 1