当前位置:网站首页>Server side resolution of lengthfieldbasedframedecoder of GetBytes

Server side resolution of lengthfieldbasedframedecoder of GetBytes

2020-11-08 19:27:06 Miss Ma

1. effect

  • LengthFieldBasedFrameDecoder The decoder is based on length The value of the field dynamically splits the received ByteBuf, Decoding binary messages ( Contains header : The length of the message stored in the header ) when , This decoder is particularly useful

2. Argument parsing

2.1 Simple to build netty Communications

2.1.1client

package cn.itbin.decode.client;

import cn.itbin.client.TelnetClientInitializer;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * @author chenxiaogao
 * @className Client
 * @description TODO
 * @date 2020/11/7
 **/
public class Client {
 static final String HOST = System.getProperty("host", "127.0.0.1");
 static final int PORT = Integer.parseInt(System.getProperty("port", "8023"));
 public static void main(String[] args) throws Exception {

 EventLoopGroup group = new NioEventLoopGroup();
 try {
 Bootstrap b = new Bootstrap();
 b.group(group)
 .channel(NioSocketChannel.class)
 .handler(new LoggingHandler(LogLevel.INFO))
 ;

 //  Start trying to connect 
 Channel ch = b.connect(HOST, PORT).sync().channel();
 String request = "HELLO, WORLD";
 ByteBuf buffer = Unpooled.buffer();
 buffer.writeShort(request.length());
 buffer.writeBytes(request.getBytes());
 ch.writeAndFlush(buffer);
 } finally {
 group.shutdownGracefully();
 }
 }
}

2.1.2server

  • server
package cn.itbin.decode.server;

import cn.itbin.server.TelnetServerInitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import java.util.Arrays;

/**
 * @author chenxiaogao
 * @className Server
 * @description TODO
 * @date 2020/11/7
 **/
public class Server {
 static final int PORT = Integer.parseInt(System.getProperty("port", "8023"));

 public static void main(String[] args) throws Exception {

 EventLoopGroup bossGroup = new NioEventLoopGroup(1);
 EventLoopGroup workerGroup = new NioEventLoopGroup();
 try {
 ServerBootstrap b = new ServerBootstrap();
 b.group(bossGroup, workerGroup)
 .channel(NioServerSocketChannel.class)
 .handler(new LoggingHandler(LogLevel.INFO))
 .childHandler(new ServerInitializer());

 b.bind(PORT).sync().channel().closeFuture().sync();
 } finally {
 bossGroup.shutdownGracefully();
 workerGroup.shutdownGracefully();
 }
 }
}

  • ServerInitializer
package cn.itbin.decode.server;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

/**
 * @author chenxiaogao
 * @className ServerInitializer
 * @description TODO
 * @date 2020/11/7
 **/
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
 @Override
 protected void initChannel(SocketChannel ch) throws Exception {
 ChannelPipeline pipeline = ch.pipeline();
 pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2));
 pipeline.addLast(new ServerHandler());
 }
}

  • ServerHandler
package cn.itbin.decode.server;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.nio.charset.Charset;

/**
 * @author chenxiaogao
 * @className ServerHandler
 * @description TODO
 * @date 2020/11/7
 **/
public class ServerHandler extends SimpleChannelInboundHandler<ByteBuf> {
 @Override
 protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
 int length = msg.readableBytes();
 System.out.println(" Total request length  = " + length);
 // First read the length bits of two bytes 
 short len = msg.readShort();
 System.out.println(" The length of the requested newspaper style  = " + len);
 System.out.println(" After reading two bytes ByteBuf = " + msg);
 // Read the message content 
 byte[] bytes = new byte[len];
 msg.readBytes(bytes, 0, len);
 String request = new String(bytes, Charset.forName("GBK"));
 System.out.println(" Style of request newspaper  = " + request);

 }
}

2.2 Parameters,

2.2.1 new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2)

lengthFieldOffset = 0
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" |
 +--------+----------------+ +--------+----------------+
 Suppose the first two bytes of the request message are the length of the message style 
 And hope that the server can receive the complete message 
 Then add the following decoder 

pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2));
 This constructor is called when the decoder is added 
public LengthFieldBasedFrameDecoder(
 int maxFrameLength,
 int lengthFieldOffset, int lengthFieldLength) {
 this(maxFrameLength, lengthFieldOffset, lengthFieldLength, 0, 0);
 }
 Then the actual parameter is 
 maxFrameLength:Integer.MAX_VALUE( The maximum length of the overall message , Including message header and message style )
 lengthFieldOffset:0( The starting index of the length field )
 lengthFieldLength :2( The length of the length field )
 lengthAdjustment : 0 
 initialBytesToStrip :0

1. Assemble the request body :
String request = "HELLO, WORLD";
// Create a byte buffer 
ByteBuf buffer = Unpooled.buffer();
// Write two bytes of the length of the message style , The length is 12
buffer.writeShort(request.length());
// Write in newspaper style 
buffer.writeBytes(request.getBytes());
// send out 
ch.writeAndFlush(buffer);
 The actual request body is :
 Information : [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. Parsing on the server side 
lengthFieldOffset:0( The starting index of the length field )
 lengthFieldLength :2( The length of the length field )
 from 0 The index begins to read two bytes for the length of the message style , The length of  00 0c  The length is 12
 @Override
 protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
 int length = msg.readableBytes();
 System.out.println(" Total request length  = " + length);
 // First read the length bits of two bytes 
 short len = msg.readShort();
 System.out.println(" The length of the requested newspaper style  = " + len);
 System.out.println(" After reading two bytes ByteBuf = " + msg);
 // Read the message content 
 byte[] bytes = new byte[len];
 msg.readBytes(bytes, 0, len);
 String request = new String(bytes, Charset.forName("GBK"));
 System.out.println(" Style of request newspaper  = " + request);

 }
 Total request length  = 14
 The length of the requested newspaper style  = 12
 After reading two bytes ByteBuf = PooledSlicedByteBuf(ridx: 2, widx: 14, cap: 14/14, unwrapped: PooledUnsafeDirectByteBuf(ridx: 14, widx: 14, cap: 1024))
 Style of request newspaper  = HELLO, WORLD

2.2.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" |
 +--------+----------------+ +----------------+

 Suppose the first two bytes of the request message are the length of the message style 
 And hope that the server only receives the newspaper style , Discard length bytes 
 Then add the following decoder 
new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2,0,2)
 Request message and 2.2.1 identical 
 

2.2.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" |
 +--------+----------------+ +--------+----------------+

 Suppose the first two bytes of the request message are the total length  
 And want the server to receive all messages 
 Then add the following decoder 
new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2,-2,0)

 Assemble the request body 
String request = "HELLO, WORLD";
ByteBuf buffer = Unpooled.buffer();
buffer.writeShort(request.length()+2);
buffer.writeBytes(request.getBytes());
 Information : [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(" Total request length  = " + length);
 // Read two byte length bits 
 short len = msg.readShort();
 System.out.println(" The total length of the message is  = " + len);
 // The request body of the message is 
 String content = msg.toString(2, len-2, Charset.defaultCharset());
 System.out.println(" The message request body is  = " + content);
 }
 Total request length  = 14
 The total length of the message is  = 14
 The message request body is  = HELLO, WORLD

The other parameters are as follows

 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" |
 +------+--------+------+----------------+ +------+----------------+
 

3 Parsing messages whose length bits are strings

  • Other message lengths are expressed in strings, such as :0002AD The first four bytes are length bits 2,AD For message content
    You need a custom decoder , rewrite getUnadjustedFrameLength
  • Change the above code as follows

3.1 Assembly request message

String request = "HELLO, WORLD";
            ByteBuf buffer = Unpooled.buffer();
 // Convert the length to 4 A string 
 String strLen = "00"+request.length();
 buffer.writeBytes(strLen.getBytes());
 buffer.writeBytes(request.getBytes());
 ch.writeAndFlush(buffer);

 Information : [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|
+--------+-------------------------------------------------+----------------+

3.2 Custom decoder

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:
 // Get four byte length bits 
 byte[] bytes = new byte[4];
// Note the use of getBytes, It won't change the original 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;
 }
}

3.3 Add custom decoder to pipleline in

public class ServerInitializer extends ChannelInitializer<SocketChannel> {
 @Override
 protected void initChannel(SocketChannel ch) throws Exception {
 ChannelPipeline pipeline = ch.pipeline();
 pipeline.addLast(new MyLFBFD(Integer.MAX_VALUE, 0, 4));
 pipeline.addLast(new ServerHandler());
 }
}

3.4 Parsing on the server side

public class ServerHandler extends SimpleChannelInboundHandler<ByteBuf> {
 @Override
 protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
 int length = msg.readableBytes();
 System.out.println(" Total request length  = " + length);
 String request = msg.toString(4, length - 4, Charset.forName("GBK"));
 System.out.println("request = " + request);
 }
}

author :www.hbfzb.com
link :https://www.hbfzb.com/
source :https://www.hbfzb.com/html/shou.php
The copyright belongs to the author . Commercial reprint please contact the author for authorization , Non-commercial reprint please indicate the source .

版权声明
本文为[Miss Ma]所创,转载请带上原文链接,感谢