1参数详解
1.1.1 new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2)
lengthFieldOffset = 0
lengthFieldLength = 2
lengthAdjustment = 0
initialBytesToStrip = 0 (= do not strip header)
lengthFieldLength = 2
lengthAdjustment = 0
initialBytesToStrip = 0 (= do not strip header)
BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes) +--------+----------------+ +--------+----------------+ | Length | Actual Content |----->| Length | Actual Content | | 0x000C | "HELLO, WORLD" | | 0x000C | "HELLO, WORLD" | +--------+----------------+ +--------+----------------+ 假设请求报文的前两个字节为报文体的长度 并希望服务端能够收到完整的报文 则加入下面这个解码器 pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2)); 当加入这个解码器时会调用这个构造方法 public LengthFieldBasedFrameDecoder( int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) { this(maxFrameLength, lengthFieldOffset, lengthFieldLength, 0, 0); } 则实际的参数为 maxFrameLength:Integer.MAX_VALUE(整体报文的最大长度,包括报文头和报文体) lengthFieldOffset:0(长度字段的起始索引) lengthFieldLength :2(长度字段的长度) lengthAdjustment : 0 initialBytesToStrip :0 1.组装请求体: String request = "HELLO, WORLD"; //创建一个字节缓冲区 ByteBuf buffer = Unpooled.buffer(); //写入两个字节的报文体长度,长度为12 buffer.writeShort(request.length()); //写入报文体 buffer.writeBytes(request.getBytes()); //发送 ch.writeAndFlush(buffer); 实际请求体为: 信息: [id: 0x87221f3a, L:/127.0.0.1:52524 - R:/127.0.0.1:8023] WRITE: 14B +-------------------------------------------------+ | 0 1 2 3 4 5 6 7 8 9 a b c d e f | +--------+-------------------------------------------------+----------------+ |00000000| 00 0c 48 45 4c 4c 4f 2c 20 57 4f 52 4c 44 |..HELLO, WORLD | +--------+-------------------------------------------------+----------------+ 2.在服务端解析 lengthFieldOffset:0(长度字段的起始索引) lengthFieldLength :2(长度字段的长度) 从0索引开始读两个字节为报文体的长度,则长度为 00 0c 即长度为12 @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { int length = msg.readableBytes(); System.out.println("请求总长度 = " + length); //首先读取两个字节的长度位 short len = msg.readShort(); System.out.println("请求报文体的长度 = " + len); System.out.println("读取两个字节后的ByteBuf = " + msg); //读取报文内容 byte[] bytes = new byte[len]; msg.readBytes(bytes, 0, len); String request = new String(bytes, Charset.forName("GBK")); System.out.println("请求报文体 = " + request); } 请求总长度 = 14 请求报文体的长度 = 12 读取两个字节后的ByteBuf = PooledSlicedByteBuf(ridx: 2, widx: 14, cap: 14/14, unwrapped: PooledUnsafeDirectByteBuf(ridx: 14, widx: 14, cap: 1024)) 请求报文体 = HELLO, WORLD
1.1.2new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2,0,2)
lengthFieldOffset = 0
lengthFieldLength = 2
lengthAdjustment = 0
initialBytesToStrip = 2 (= the length of the Length field)
BEFORE DECODE (14 bytes) AFTER DECODE (12 bytes) +--------+----------------+ +----------------+ | Length | Actual Content |----->| Actual Content | | 0x000C | "HELLO, WORLD" | | "HELLO, WORLD" | +--------+----------------+ +----------------+ 假设请求报文的前两个字节为报文体的长度 并希望服务端只接收报文体,丢弃掉长度字节 则加入下面这个解码器 new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2,0,2) 请求报文与2.2.1相同 @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { int length = msg.readableBytes(); System.out.println("请求总长度 = " + length); String s = msg.toString(0, length, Charset.defaultCharset()); System.out.println("请求报文体 = " + s); } 请求总长度 = 12 请求报文体 = HELLO, WORLD
1.1.3new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2,-2,0);
lengthFieldOffset = 0
lengthFieldLength = 2
lengthAdjustment = -2 (= the length of the Length field)
initialBytesToStrip = 0
BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes) +--------+----------------+ +--------+----------------+ | Length | Actual Content |----->| Length | Actual Content | | 0x000E | "HELLO, WORLD" | | 0x000E | "HELLO, WORLD" | +--------+----------------+ +--------+----------------+ 假设请求报文的前两个字节为总体的长度 并希望服务端接收全部报文 则加入下面这个解码器 new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2,-2,0) 组装请求体 String request = "HELLO, WORLD"; ByteBuf buffer = Unpooled.buffer(); buffer.writeShort(request.length()+2); buffer.writeBytes(request.getBytes()); 信息: [id: 0xa51d3b17, L:/127.0.0.1:56298 - R:/127.0.0.1:8023] WRITE: 14B +-------------------------------------------------+ | 0 1 2 3 4 5 6 7 8 9 a b c d e f | +--------+-------------------------------------------------+----------------+ |00000000| 00 0e 48 45 4c 4c 4f 2c 20 57 4f 52 4c 44 |..HELLO, WORLD | +--------+-------------------------------------------------+----------------+ @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { int length = msg.readableBytes(); System.out.println("请求总长度 = " + length); //读取两个字节的长度位 short len = msg.readShort(); System.out.println("报文总长度为 = " + len); //报文的请求体为 String content = msg.toString(2, len-2, Charset.defaultCharset()); System.out.println("报文请求体为 = " + content); } 请求总长度 = 14 报文总长度为 = 14 报文请求体为 = HELLO, WORLD
其他几个参数如下:
lengthFieldOffset = 2 (= the length of Header 1) lengthFieldLength = 3 lengthAdjustment = 0 initialBytesToStrip = 0 BEFORE DECODE (17 bytes) AFTER DECODE (17 bytes) +----------+----------+----------------+ +----------+----------+----------------+ | Header 1 | Length | Actual Content |----->| Header 1 | Length | Actual Content | | 0xCAFE | 0x00000C | "HELLO, WORLD" | | 0xCAFE | 0x00000C | "HELLO, WORLD" | +----------+----------+----------------+ +----------+----------+----------------+ lengthFieldOffset = 0 lengthFieldLength = 3 lengthAdjustment = 2 (= the length of Header 1) initialBytesToStrip = 0 BEFORE DECODE (17 bytes) AFTER DECODE (17 bytes) +----------+----------+----------------+ +----------+----------+----------------+ | Length | Header 1 | Actual Content |----->| Length | Header 1 | Actual Content | | 0x00000C | 0xCAFE | "HELLO, WORLD" | | 0x00000C | 0xCAFE | "HELLO, WORLD" | +----------+----------+----------------+ +----------+----------+----------------+ lengthFieldOffset = 1 (= the length of HDR1) lengthFieldLength = 2 lengthAdjustment = 1 (= the length of HDR2) initialBytesToStrip = 3 (= the length of HDR1 + LEN) BEFORE DECODE (16 bytes) AFTER DECODE (13 bytes) +------+--------+------+----------------+ +------+----------------+ | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content | | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" | | 0xFE | "HELLO, WORLD" | +------+--------+------+----------------+ +------+----------------+ lengthFieldOffset = 1 lengthFieldLength = 2 lengthAdjustment = -3 (= the length of HDR1 + LEN, negative) initialBytesToStrip = 3 BEFORE DECODE (16 bytes) AFTER DECODE (13 bytes) +------+--------+------+----------------+ +------+----------------+ | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content | | 0xCA | 0x0010 | 0xFE | "HELLO, WORLD" | | 0xFE | "HELLO, WORLD" | +------+--------+------+----------------+ +------+----------------+
2解析长度位为字符串的报文
- 还有的报文长度是用字符串表示的例如:0002AD 前四个字节表示长度位2,AD为报文内容
则需要自定义解码器,重写getUnadjustedFrameLength - 将上述代码做如下修改
String request = "HELLO, WORLD"; ByteBuf buffer = Unpooled.buffer(); //将长度转化为4位字符串 String strLen = "00"+request.length(); buffer.writeBytes(strLen.getBytes()); buffer.writeBytes(request.getBytes()); ch.writeAndFlush(buffer); 信息: [id: 0x82110268, L:/127.0.0.1:57369 - R:/127.0.0.1:8023] WRITE: 16B +-------------------------------------------------+ | 0 1 2 3 4 5 6 7 8 9 a b c d e f | +--------+-------------------------------------------------+----------------+ |00000000| 30 30 31 32 48 45 4c 4c 4f 2c 20 57 4f 52 4c 44 |0012HELLO, WORLD| +--------+-------------------------------------------------+----------------+
2.2自定义解码器
package cn.itbin.decode.server; import io.netty.buffer.ByteBuf; import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import java.nio.ByteOrder; /** * @author chenxiaogao * @className MyLFBFD * @description TODO * @date 2020/11/8 **/ public class MyLFBFD extends LengthFieldBasedFrameDecoder { public MyLFBFD(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) { super(maxFrameLength, lengthFieldOffset, lengthFieldLength); } @Override protected long getUnadjustedFrameLength(ByteBuf buf, int offset, int length, ByteOrder order) { buf = buf.order(order); long frameLength; switch (length) { case 1: frameLength = buf.getUnsignedByte(offset); break; case 2: frameLength = buf.getUnsignedShort(offset); break; case 3: frameLength = buf.getUnsignedMedium(offset); break; case 4: //获取四个字节长度位 byte[] bytes = new byte[4]; //注意此处使用getBytes,不会改变原有的ByteBuf buf.getBytes(0, bytes); String strLen = new String(bytes); frameLength = Long.valueOf(strLen); break; case 8: frameLength = buf.getLong(offset); break; default: throw new DecoderException( "unsupported lengthFieldLength: " + length + " (expected: 1, 2, 3, 4, or 8)"); } return frameLength; } }