前言:
当前你们对“netty 教程”大致比较关怀,兄弟们都需要了解一些“netty 教程”的相关内容。那么小编同时在网上汇集了一些对于“netty 教程””的相关知识,希望兄弟们能喜欢,小伙伴们快快来了解一下吧!1 实际开发过程中,我们会自定义一个传输协议,说简单点就是发送方和接收方统一一个规则,比如发送的报文中包括以下字段:
1 魔鬼数字
2 版本号
3 序列化算法类型
4 指令类型
5 请求序列号
6 消息内容长度
7 消息内容
最好1,2,3,4,5,6的字节长度加起来是2的指数倍,这样看起来专业一点
比如我这里发送的是一个登陆的消息:
上代码:
package com.study.nio.ph2.e7;import lombok.AllArgsConstructor;import lombok.Data;/** * @program: isc-study * * @description: * * @author: wangjinwei * * @create: 2021-11-04 14:15 **/@Data@AllArgsConstructorpublic class LoginRequestMessage extends Message { private String loginname; private String password; private String nickname; @Override public Byte getMessageType() { return 1; } @Override public int getSequenceId() { return 0; }}package com.study.nio.ph2.e7;import java.io.Serializable;public abstract class Message implements Serializable { /** * 消息类型 * @return */ public abstract Byte getMessageType(); /** * 字节序列 * @return */ public abstract int getSequenceId();}package com.study.nio.ph2.e7;import io.netty.buffer.ByteBuf;import io.netty.channel.ChannelHandlerContext;import io.netty.handler.codec.ByteToMessageCodec;import lombok.extern.slf4j.Slf4j;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.util.List;/** * @program: isc-study * @description: 自定义协议 编解码 * @author: wangjinwei * @create: 2021-11-04 14:11 **/@Slf4jpublic class MessageCodec extends ByteToMessageCodec<Message> { @Override protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception { //1 4个字节魔数 out.writeBytes(new byte[]{1, 2, 3, 4}); //2 1个字节的版本 out.writeByte(2); //3 1个字节的序列化方式 jdk 0 , json 1 out.writeByte(0); //4 1个字节的指令类型 out.writeByte(msg.getMessageType()); //5 4个字节的序列 out.writeInt(msg.getSequenceId()); // 无意义,对齐填充 凑齐2的指数倍 out.writeByte(0xff); //内容转换成字节数组 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(msg); byte[] bytes = bos.toByteArray(); // 6 4个字节写入长度 out.writeInt(bytes.length); // 7 写入内容 out.writeBytes(bytes); } @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { int magicNum = in.readInt(); byte version = in.readByte(); byte seriType = in.readByte(); byte messageType = in.readByte(); int seq = in.readInt(); in.readByte(); int len = in.readInt(); byte[] bytes = new byte[len]; in.readBytes(bytes, 0, len); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes)); Message message = (Message) ois.readObject(); System.out.printf("magicNum=%s, version=%s, seriType=%s, messageType=%s, seq=%d, len=%d", magicNum, version, seriType, messageType, seq, len); log.info("{}", message); out.add(message); }}@Slf4jpublic class TestMessage { public static void main(String[] args) throws Exception { EmbeddedChannel channel = new EmbeddedChannel( new LoggingHandler(LogLevel.INFO), new MessageCodec() ); LoginRequestMessage message = new LoginRequestMessage("zhangsan", "123", "张三"); ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(); new MessageCodec().encode(null,message,buf); channel.writeInbound(buf); }}
运行结果如下:
这里为了安全起见,加入一个LengthFieldBasedFrameDecoder,这样才不会发生拆包粘包
修改代码:
package com.study.nio.ph2.e7;import io.netty.buffer.ByteBuf;import io.netty.buffer.ByteBufAllocator;import io.netty.channel.embedded.EmbeddedChannel;import io.netty.handler.codec.LengthFieldBasedFrameDecoder;import io.netty.handler.logging.LogLevel;import io.netty.handler.logging.LoggingHandler;import lombok.extern.slf4j.Slf4j;/** * @program: isc-study * @description: * @author: wangjinwei * @create: 2021-11-04 16:06 **/@Slf4jpublic class TestMessage { public static void main(String[] args) throws Exception { EmbeddedChannel channel = new EmbeddedChannel( new LoggingHandler(LogLevel.INFO), new LengthFieldBasedFrameDecoder(1024,12,4,0,0), new MessageCodec() ); LoginRequestMessage message = new LoginRequestMessage("zhangsan", "123", "张三"); ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(); new MessageCodec().encode(null,message,buf);// channel.writeInbound(buf); ByteBuf s1 = buf.slice(0, 100); ByteBuf s2 = buf.slice(100, buf.readableBytes() - 100); s1.retain(); // 引用计数 2 channel.writeInbound(s1); // release 1 channel.writeInbound(s2); }}
如果不加入LengthFieldBasedFrameDecoder就报错了
标签: #netty 教程