Netty自定义协议

先写一个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'}

一个简单的协议就写好了

视频

源码