Netty was used in the work of server development. When the server received more than 1000 bytes of upper computer, the server received data error. For what server to receive data sometimes no problem, sometimes receive data chaos. In constant testing and consolidation of Netty knowledge points, Netty has a new thinking in the project development.

In TCP communication must appear sticky packet, unpack problem? If not, when does the problem of sticking and unpacking occur? If the server receives more than 1000 bytes at a time and the byteBuf capacity is less than 1000 bytes, what is the problem? How to solve it?

Notes (Netty Series)

If you want to be a beginner in network programming and Netty, check out the list of three articles. 1 Layer 7 protocol and TCP/IP protocol, three handshake and four wave, BIO, NIO(Netty front) 2 article introduction Netty (Netty first) 3 How to choose codec in project development? How to solve the PROBLEM of TCP sticky packets? (Netty 2)

GitHub code address gitee code address

A sticky packet (server to client communication)

1.1 Example No sticky packets appear

1.1.1 Code implementation

The client sends the same byte array to the server every 500 milliseconds, and the server converts the received byte into a string and prints it. 1. Configuration classes on the server

public class TcpServer { private final int port; public TcpServer(int port) { this.port = port; } public void init() { NioEventLoopGroup boss = new NioEventLoopGroup(); NioEventLoopGroup work = new NioEventLoopGroup(); ServerBootstrap = new ServerBootstrap(); // Bootstrap. group(boss, work); / / the bootstrap configuration thread group. The channel (NioServerSocketChannel. Class); Bootstrap. childHandler(new ChannelInitializer<SocketChannel>() {protected void InitChannel (SocketChannel CH) throws Exception {// Bind the channel parameter ch.pipeline().addlast ("logging", new LoggingHandler("DEBUG")); Ch.pipeline ().addlast ("encode", new EncoderHandler())); // encoder. Ch.pipeline ().addlast ("decode", new DecoderHandler()); Ch.pipeline ().addlast ("handler", new TcpServerHandler()); // Business processing class, the final message is processed in the handler}}); ChannelFuture = bootstrap.bind(port).sync(); // Asynchronously close the port future.channel().closeFuture().sync(); } catch (Exception e) { } finally { work.shutdownGracefully(); Box.shutdownexceptionexceptionexception () causes the thread group to be disabled. }}}Copy the code

2. Server decoder (decode)

public class DecoderHandler extends ByteToMessageDecoder { protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {system.out.println ("byteBuf's capacity is: "+ in.capacity()); System.out.println("byteBuf is readable: "+ in.readableBytes()); System.out.println("byteBuf writable capacity: "+ in.writableBytes()); byte[] data = new byte[in.readableBytes()]; // Read core data in.readbytes (data); out.add(data); }}Copy the code

3. Server encoder (encode)

public class EncoderHandler extends MessageToByteEncoder { protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { out.writeBytes((byte[]) msg); }}Copy the code

4. ChannelHandler on the server

public class TcpServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { byte[] recevierByte = (byte[]) msg; String recevierString = ByteTransform.bytesToHexString(recevierByte); System. The out. Println (" -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- length is: "+ recevierString. The length ()); System.out.println("-- TCP service accepts device-side encrypted data: "+ recevierString); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { super.channelActive(ctx); } /** * Override public void channelInactive(ChannelHandlerContext CTX) throws Exception { super.channelInactive(ctx); } /** * Public void exceptionCaught(ChannelHandlerContext CTX, Throwable cause) throws Exception { super.exceptionCaught(ctx, cause); }}Copy the code

5. Start the server class

public class StartServer { public static void main(String[] args) { try { new TcpServer(5566).init(); } catch (Exception e) { e.printStackTrace(); }}}Copy the code

6. Utility classes (if you know what methods are)

Public class ByteTransformIntUtil {/** * public static int getIntFromBytes(byte high_h, byte high_l, byte low_h, byte low_l) { return (high_h & 0xff) << 24 | (high_l & 0xff) << 16 | (low_h & 0xff) << 8 | low_l & 0xff; } /** * public static int getIntFromBytes(byte low_h, byte low_l) { return ByteTransformIntUtil.getIntFromBytes((byte)0,(byte)0,low_h,low_l); }}Copy the code

7. Configuration classes of the client

public class MyRPCClient { public void start(String host, Throws Exception {// Define a thread group EventLoopGroup worker = new NioEventLoopGroup(); Bootstrap = new Bootstrap(); Bootstrap.group (worker).channel(niosocketchannel.class) Handler (new ChannelInitializer<SocketChannel>() {@override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new MyClientHandler()); }}); ChannelFuture = bootstrap.connect(host, port).sync(); future.channel().closeFuture().sync(); } finally { worker.shutdownGracefully(); }}}Copy the code

8. Client startup classes

public class StartClient { public static void main(String[] args) { new Thread() { public void run() { try { new MyRPCClient (.) start (" 127.0.0.1 ", 5566); } catch (Exception e) { e.printStackTrace(); } } }.start(); }}Copy the code

9. Client ChannelHandler

public class MyClientHandler extends SimpleChannelInboundHandler<Object> { @Override protected void channelRead0(ChannelHandlerContext ctx, Object buf) throws Exception { } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // Timer = new Timer(); final byte[] bytes = ByteTransform.hexStringToBytes("10000000"); Timer. ScheduleAtFixedRate (new TimerTask () {public void the run () {byte [] msg1 = {0 x00 to 0 x00 to 0 x00 to 0 x00 to 0 x01, 0 x01, 0 x02, 0 x01}; ctx.writeAndFlush(Unpooled.copiedBuffer(msg1)); }}, 5000, 50); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } public int getIntFromBytes(byte high_h, byte high_l, byte low_h, byte low_l) { return (high_h & 0xff) << 24 | (high_l & 0xff) << 16 | (low_h & 0xff) << 8 | low_l & 0xff; }}Copy the code

1.1.2 Analyze the results

The Handler on the client sends data to the server at 50-millisecond intervals. However, there is no sticky packet problem on the server.

conclusionThe client sends data to the server at an interval without sticky packets.

1.2 Sticky packages occur

1.2.1 Code examples

The client continuously sends a byte array (16 bytes) to the server.

  1. Client ChannelHandler (just replace MyClientHandler with the client above, the rest of the code remains the same)
public class MyClientHandler extends SimpleChannelInboundHandler<Object> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object buf) throws Exception {

    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
       
        while (true){
            i = i + 1;
            byte[] msg = {0x00, 0x00, 0x00, 0x0c, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109, 98};
            ctx.writeAndFlush(Unpooled.copiedBuffer(msg));
        }
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    public int getIntFromBytes(byte high_h, byte high_l, byte low_h, byte low_l) {
        return (high_h & 0xff) << 24 | (high_l & 0xff) << 16 | (low_h & 0xff) << 8 | low_l & 0xff;
    }
}
Copy the code

1.2.2 Analysis of the results

The client continuously sends a byte array (16 bytes) to the server, and the service prints out the received bytes.



Phenomenon:The length of bytes read each time changes.

Conclusion:Sticky packets may occur if a client colleague receives multiple data.

Two unpacking

2.1 There is no unpacking problem

2.1.1 Code implementation

public class MyClientHandler extends SimpleChannelInboundHandler<Object> { @Override protected void channelRead0(ChannelHandlerContext ctx, Object buf) throws Exception { } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // Timer = new Timer(); final byte[] bytes = ByteTransform.hexStringToBytes("10000000"); Timer. ScheduleAtFixedRate (new TimerTask () {public void the run () {byte [] msg1 = {0 x00 to 0 x00 to 0 x00 to 0 x00 to 0 x01, 0 x01, 0 x02, 0 x01}; ctx.writeAndFlush(Unpooled.copiedBuffer(msg1)); }}, 5000, 50); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } public int getIntFromBytes(byte high_h, byte high_l, byte low_h, byte low_l) { return (high_h & 0xff) << 24 | (high_l & 0xff) << 16 | (low_h & 0xff) << 8 | low_l & 0xff; }}Copy the code

2.1.2 Result analysis



The Handler on the client sends data to the server at 50-millisecond intervals. However, there is no sticky packet problem on the server.

conclusionThe client sends a byte array (a dozen bytes) to the server without unpacking.

2.2 Instance Netty Unpacking (1)

public class MyClientHandler extends SimpleChannelInboundHandler<Object> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object buf) throws Exception {
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 向服务端发送数据
        Timer timer = new Timer();
        final byte[] bytes = ByteTransform.hexStringToBytes("10000000");
        timer.scheduleAtFixedRate(new TimerTask() {
            public void run() {
                byte[] msg = {0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                            0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                            0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                            0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                            0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                            0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                            0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                            0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                            0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                            0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                            0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                            0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                            0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                            0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,


                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                        0x01, 98, 49, 50, 51, 52, 53, 54, 0x12, 0x11, 0x11, 0x00, 0x00, 109, 109,
                };
                ctx.writeAndFlush(Unpooled.copiedBuffer(msg));
            }
        }, 5000, 1000);
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    public int getIntFromBytes(byte high_h, byte high_l, byte low_h, byte low_l) {
        return (high_h & 0xff) << 24 | (high_l & 0xff) << 16 | (low_h & 0xff) << 8 | low_l & 0xff;
    }

}
Copy the code



The phenomenon ofAfter the server receives the data from the client, the server receives the data of fixed length. The sum after the first two data lengths is the sum of the following data lengths.

Analysis of theThe initial capacity of ByteBuf is a random value ranging from 300 to 1024. When the length of received data is larger than the capacity of ByteBuf,ByteBuf receives data twice. Cause unpacking effect.

Solve the problem of sticking and unpacking

Scheme 2.1 a

2.1.1 Code implementation

The idea is to add a fixed header before transferring data, storing the length of data. Read the specified length each time.

  1. Server decode
public class DecoderHandler extends ByteToMessageDecoder { protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {system.out.println ("byteBuf's capacity is: "+ in.capacity()); System.out.println("byteBuf is readable: "+ in.readableBytes()); System.out.println("byteBuf writable capacity: "+ in.writableBytes()); int len = ByteTransformIntUtil.getIntFromBytes(in.readByte(), in.readByte()); byte[] data = new byte[len]; // Read core data in.readbytes (data); out.add(data); }}Copy the code
  1. Client-side Handler

2.1.2 Analysis of the results

The phenomenon ofAn error occurred on the server. Procedure

Analysis of theThe length of bytes fetched from ByteBuf is larger than the capacity of ByteBuf because the data passed by the client is more than 1000 bytes long.

The code analysis

/ / regulations, the client transfer the data length of int len = ByteTransformIntUtil. GetIntFromBytes (in the readByte (), in the readByte ()); Byte [] data = new byte[len]; // Read core data in.readbytes (data);Copy the code

ChennelPipeline (chennelPipeline) executes each ChannelHandler from the first ChannelHandler to the end of the pipeline. Go to war from the end to the end. But when outbound, the decoder is not executed. Encoder is not executed when entering the station. I use the code debug to debug, here is a demonstration. You can write your own demo if you are interested.

2.2 Solution 2 (Solved)

2.2.1 Code implementation

Solution 1: The length of the transmitted data is larger than that of ByteBuf. Let the read return if the received data length is greater than the BetuBuf length. And the next read together.(this will solve the data read incomplete, also solve the data sticky packet)

    1. Server decode
public class DecoderHandler extends ByteToMessageDecoder { protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {system.out.println ("byteBuf's capacity is: "+ in.capacity()); System.out.println("byteBuf is readable: "+ in.readableBytes()); System.out.println("byteBuf writable capacity: "+ in.writableBytes()); // Place the current ByteBuf read pointer in a variable m in.markReaderIndex(); int len = ByteTransformIntUtil.getIntFromBytes(in.readByte(), in.readByte()); System.out.println(" Data length: "+ len); If (len > in.readableBytes()){// Restore the read pointer to the value of the variable just marked in.resetreaderIndex (); // If the received data length is greater than the ByteBuf length, the data is not read this time and the next time. } byte[] data = new byte[len]; // Read core data in.readbytes (data); out.add(data); }}Copy the code

2.2.2 Analysis of the results

The client continuously sends bytes of data (1710 bytes in length) to the server, and the server prints the received data

The phenomenon ofThe server print byte array is 1710 bytes long.

conclusionThis solution solves the problem of sticky packets and unpacking packets when TCP uses Netty.

2.2.3 Source Code (Final solution)

GitHub code address (click to obtain) Gitee code address

Denver annual essay | 2020 technical way with me The campaign is under way…