Netty中半包粘包的产生与处理:短连接、固定长度、固定分隔符、预设长度;redis、http协议举例;网络数据的发送和接收过程

目录

粘包、半包

相关概念

网络数据发送和接收过程

Netty半包粘包解决方案

ByteBuf获取和默认大小

短链接

固定长度

固定分隔符

预设长度 

常见协议代码举例

redis协议

http协议 

 参考链接

粘包、半包

相关概念

        程序处理过程中我们会通过缓冲区接收数据,接收的过程中可能会出现所谓的粘包和半包的问题。

        当发送方发送数据大小小于接收方缓冲区大小且接收方来不及处理缓冲区中的内容,此时可能发生发送方发送多个完整的消息到接收方缓冲区中,接收方误将其作为一次发送的消息处理,此时产生粘包现象。

        当发送方数据大小大于接收方缓冲区大小时,发送方数据并不能一次全部发送到接收方缓冲区中,此时发送方数据就会被拆分为不同的数据大小进行发送,此时产生半包现象。

网络数据发送和接收过程

        通信过程有一个客户端和一个接收端,站在客户端角度来讲,我们可以分为这样的几个层次,用户区或者叫用户态,系统区或者内核区或者叫内核态,再往下是硬件或则叫网卡。

        Java程序是在用户区,socketChnnel.write(byte)这个时候就是把数据复制到我们的内核态当中,然后操作系统将数据再次拷贝给网卡,网卡操作数据可以传递出去。真正发送的时候会以数据包的形式进行发送,当然数据包的这个概念是不准确的,应该叫做数据帧。
        接收方数据拿到之后,由网卡拿到数据之后将数据拷贝到操作系统的数据的缓冲区,也就是socket的缓冲区,当我们调用一些读的方法的时候,Socket缓冲区的数据会拷贝到我们的用户区里边。

        用户内存和我们的Socket的缓冲区这两个都有可能产生一个半包粘包的问题(数据要么存少了,要么存多了)

        DMA(Direct Memory Access)直接内存访问,是一种计算机硬件特性,允许某些硬件设备(磁盘驱动器、网络接口卡等)直接向内存传输数据,而不需要中央处理器CPU的介入。能够显著提高数据传输的效率,能够减少CPU负载,允许CPU在数据传输期间执行其他任务。

Netty半包粘包解决方案

        粘包:是由于数据发送太快,接收方byteBuf太大。

        半包:MSS、接收方byteBuf太小。

ByteBuf获取和默认大小

        ByteBuf是Netty通过Handler帮我们创建的(第一个非head的InboundHandler获取的参数就是Netty获取的数据),Netty接收数据帮我们创建的ByteBuf的大小默认是1024B,可以指定最小字节16,同时也可以指定(最小值、初始值、最大值)。

        我们可以人为地设置Socket缓冲区和ByteBuf缓冲区,从而更好地验证Netty在网络传输中出现的半包、粘包现象以及其解决方案。

        Soket缓冲区的改变是一个全局的概念。ChannelOption.SO_REVBUF代表的是接收缓冲区的大小。channelOption.SO_SNDBUF代表的是发送缓冲区的大小。SO代表的是Socket,通过这种方式所做的修改是在应用程序层面做出的修改,不会上升到全局的角度,这样不会影响到操作系统下其他的TCP协议通信的程序。

短链接

        短链接:发一个包建立一个连接,这样连接建立到断开之间就是消息边界。人为的让连接建立和断开,连接断开后服务端读取到的消息长度为-1,此时服务器端就知道客户端断开,读取的消息为一次完整的消息。

        局限性:发一次包建立一次连接,效率太低;短连接能够解决粘包问题,当ByteBuf太小时,对于半包的处理无能为力。

        服务器端代码:

@Slf4j
public class HelloServer {
    public static void main(String[] args) {
        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.group(boss, worker);
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    socketChannel.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
                }
            });
            ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("Server error ", e);
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}

        客户端代码:

public class HelloClient {
    static final Logger log = LoggerFactory.getLogger(HelloClient.class);
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            send();
        }
    }

    private static void send() {
        NioEventLoopGroup worker = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(worker);
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    socketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                        // channelActive会在连接channel建立成功后,会触发 active事件
                        @Override
                        public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                ByteBuf buffer = ctx.alloc().buffer(10);
                                buffer.writeBytes(new byte[]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15});
                                ctx.writeAndFlush(buffer);
                                ctx.channel().close();
                        }
                    });
                }
            });
            ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress("localhost", 8080));
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            log.info("clinet error ", e);
        } finally {
            worker.shutdownGracefully();
        }
    }
}

        结果:

00:01:43.237 [nioEventLoopGroup-3-8] INFO io.netty.handler.logging.LoggingHandler - [id: 0x700958ce, L:/127.0.0.1:8080 - R:/127.0.0.1:62462] READ COMPLETE
00:01:43.237 [nioEventLoopGroup-3-8] INFO io.netty.handler.logging.LoggingHandler - [id: 0x700958ce, L:/127.0.0.1:8080 - R:/127.0.0.1:62462] READ COMPLETE
00:01:43.237 [nioEventLoopGroup-3-8] INFO io.netty.handler.logging.LoggingHandler - [id: 0x700958ce, L:/127.0.0.1:8080 ! R:/127.0.0.1:62462] INACTIVE
00:01:43.238 [nioEventLoopGroup-3-8] INFO io.netty.handler.logging.LoggingHandler - [id: 0x700958ce, L:/127.0.0.1:8080 ! R:/127.0.0.1:62462] UNREGISTERED
00:01:43.255 [nioEventLoopGroup-3-9] INFO io.netty.handler.logging.LoggingHandler - [id: 0xc73537e9, L:/127.0.0.1:8080 - R:/127.0.0.1:62591] REGISTERED
00:01:43.256 [nioEventLoopGroup-3-9] INFO io.netty.handler.logging.LoggingHandler - [id: 0xc73537e9, L:/127.0.0.1:8080 - R:/127.0.0.1:62591] ACTIVE
00:01:43.268 [nioEventLoopGroup-3-9] INFO io.netty.handler.logging.LoggingHandler - [id: 0xc73537e9, L:/127.0.0.1:8080 - R:/127.0.0.1:62591] READ: 16B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................|
+--------+-------------------------------------------------+----------------+
00:01:43.268 [nioEventLoopGroup-3-9] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded inbound message SimpleLeakAwareByteBuf(PooledUnsafeDirectByteBuf(ridx: 0, widx: 16, cap: 1024)) that reached at the tail of the pipeline. Please check your pipeline configuration.
00:01:43.268 [nioEventLoopGroup-3-9] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded message pipeline : [LoggingHandler#0, DefaultChannelPipeline$TailContext#0]. Channel : [id: 0xc73537e9, L:/127.0.0.1:8080 - R:/127.0.0.1:62591].
00:01:43.268 [nioEventLoopGroup-3-9] INFO io.netty.handler.logging.LoggingHandler - [id: 0xc73537e9, L:/127.0.0.1:8080 - R:/127.0.0.1:62591] READ COMPLETE
00:01:43.268 [nioEventLoopGroup-3-9] INFO io.netty.handler.logging.LoggingHandler - [id: 0xc73537e9, L:/127.0.0.1:8080 - R:/127.0.0.1:62591] READ COMPLETE
00:01:43.268 [nioEventLoopGroup-3-9] INFO io.netty.handler.logging.LoggingHandler - [id: 0xc73537e9, L:/127.0.0.1:8080 ! R:/127.0.0.1:62591] INACTIVE
00:01:43.268 [nioEventLoopGroup-3-9] INFO io.netty.handler.logging.LoggingHandler - [id: 0xc73537e9, L:/127.0.0.1:8080 ! R:/127.0.0.1:62591] UNREGISTERED
00:01:43.285 [nioEventLoopGroup-3-10] INFO io.netty.handler.logging.LoggingHandler - [id: 0xcd634dbe, L:/127.0.0.1:8080 - R:/127.0.0.1:62720] REGISTERED
00:01:43.285 [nioEventLoopGroup-3-10] INFO io.netty.handler.logging.LoggingHandler - [id: 0xcd634dbe, L:/127.0.0.1:8080 - R:/127.0.0.1:62720] ACTIVE
00:01:43.298 [nioEventLoopGroup-3-10] INFO io.netty.handler.logging.LoggingHandler - [id: 0xcd634dbe, L:/127.0.0.1:8080 - R:/127.0.0.1:62720] READ: 16B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................|
+--------+-------------------------------------------------+----------------+
00:01:43.298 [nioEventLoopGroup-3-10] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded inbound message PooledUnsafeDirectByteBuf(ridx: 0, widx: 16, cap: 1024) that reached at the tail of the pipeline. Please check your pipeline configuration.
00:01:43.298 [nioEventLoopGroup-3-10] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded message pipeline : [LoggingHandler#0, DefaultChannelPipeline$TailContext#0]. Channel : [id: 0xcd634dbe, L:/127.0.0.1:8080 - R:/127.0.0.1:62720].
00:01:43.298 [nioEventLoopGroup-3-10] INFO io.netty.handler.logging.LoggingHandler - [id: 0xcd634dbe, L:/127.0.0.1:8080 - R:/127.0.0.1:62720] READ COMPLETE
00:01:43.298 [nioEventLoopGroup-3-10] INFO io.netty.handler.logging.LoggingHandler - [id: 0xcd634dbe, L:/127.0.0.1:8080 - R:/127.0.0.1:62720] READ COMPLETE
00:01:43.299 [nioEventLoopGroup-3-10] INFO io.netty.handler.logging.LoggingHandler - [id: 0xcd634dbe, L:/127.0.0.1:8080 ! R:/127.0.0.1:62720] INACTIVE
00:01:43.299 [nioEventLoopGroup-3-10] INFO io.netty.handler.logging.LoggingHandler - [id: 0xcd634dbe, L:/127.0.0.1:8080 ! R:/127.0.0.1:62720] UNREGISTERED

固定长度

        固定长度首先约定发送方发送的所有数据包长度固定,均为一个常量,随后接收方借助定长解码器【FixedLengthFrameDecoder】解析获取到的定长消息。

         FixedLengthFrameDecoder:接收方收到数据后首先将其缓存起来,随后提取固定长度后解码处理。

        可以通过如下命令设置接收方的定长解码器:

socketChannel.pipeline().addLast(new FixedLengthFrameDecoder(10));

        服务端代码:

@Slf4j
public class HelloServer {
    public static void main(String[] args) {
        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.group(boss, worker);
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    socketChannel.pipeline().addLast(new FixedLengthFrameDecoder(10));
                    socketChannel.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
                }
            });
            ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("Server error ", e);
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}

        客户端代码:

public class HelloClient {
    static final Logger log = LoggerFactory.getLogger(HelloClient.class);
    public static void main(String[] args) {
            send();
    }

    private static byte[] fillChar(char ch, int lenght){
        byte[] ans = new byte[10];
        Arrays.fill(ans, (byte) '_');
        for(int i = 0; i < lenght; i++){
            ans[i] = ((byte) ch);
        }
        for (int i = 0; i < ans.length; i++) {
            System.out.print((char) ans[i]);
        }
        System.out.println();
        return ans;
    }

    private static void send() {
        NioEventLoopGroup worker = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(worker);
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    socketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                        // channelActive会在连接channel建立成功后,会触发 active事件
                        @Override
                        public void channelActive(ChannelHandlerContext ctx) throws Exception {
                            ByteBuf buffer = ctx.alloc().buffer(10);
                            for (int i = 0; i < 10; i++) {
                                char ch = (char) ('a' + i);
                                buffer.writeBytes(fillChar(ch, i + 1));
//                                ctx.channel().close();
                            }
                            ctx.writeAndFlush(buffer);
                        }
                    });
                }
            });
            ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress("localhost", 8080));
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            log.info("clinet error ", e);
        } finally {
            worker.shutdownGracefully();
        }
    }
}

        结果: 

00:10:24.650 [nioEventLoopGroup-3-1] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded inbound message PooledSlicedByteBuf(ridx: 0, widx: 10, cap: 10/10, unwrapped: PooledUnsafeDirectByteBuf(ridx: 40, widx: 100, cap: 1024)) that reached at the tail of the pipeline. Please check your pipeline configuration.
00:10:24.650 [nioEventLoopGroup-3-1] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded message pipeline : [FixedLengthFrameDecoder#0, LoggingHandler#0, DefaultChannelPipeline$TailContext#0]. Channel : [id: 0x4824e86f, L:/127.0.0.1:8080 - R:/127.0.0.1:64332].
00:10:24.650 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x4824e86f, L:/127.0.0.1:8080 - R:/127.0.0.1:64332] READ: 10B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 65 65 65 65 65 5f 5f 5f 5f 5f                   |eeeee_____      |
+--------+-------------------------------------------------+----------------+
00:10:24.650 [nioEventLoopGroup-3-1] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded inbound message PooledSlicedByteBuf(ridx: 0, widx: 10, cap: 10/10, unwrapped: PooledUnsafeDirectByteBuf(ridx: 50, widx: 100, cap: 1024)) that reached at the tail of the pipeline. Please check your pipeline configuration.
00:10:24.650 [nioEventLoopGroup-3-1] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded message pipeline : [FixedLengthFrameDecoder#0, LoggingHandler#0, DefaultChannelPipeline$TailContext#0]. Channel : [id: 0x4824e86f, L:/127.0.0.1:8080 - R:/127.0.0.1:64332].
00:10:24.650 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x4824e86f, L:/127.0.0.1:8080 - R:/127.0.0.1:64332] READ: 10B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 66 66 66 66 66 66 5f 5f 5f 5f                   |ffffff____      |
+--------+-------------------------------------------------+----------------+

固定分隔符

        发送方发送数据后在数据末尾添加固定标识,用以向接收方严明此位置为数据的结束位置,随后接收方根据特定的分隔符分割并接收数据。

        固定分隔符主要有以下两个类别:

  • LineBasedFrameDecoder:默认以'\n'或者'\r\n'作为分隔符。
    DelimiterBasedFrameDecoder :支持自定义分隔符。

        上述两种分隔符使用的时候均需要设置最大长度,达到最大长度后仍然没有出现分隔符,则抛出异常。

        服务端代码:

@Slf4j
public class HelloServer {
    public static void main(String[] args) {
        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.group(boss, worker);
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    socketChannel.pipeline().addLast(new LineBasedFrameDecoder(1024));
                    socketChannel.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
                }
            });
            ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("Server error ", e);
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}

        客户端代码:

public class HelloClient {
    static final Logger log = LoggerFactory.getLogger(HelloClient.class);
    public static void main(String[] args) {
            send();
    }

    private static void send() {
        NioEventLoopGroup worker = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(worker);
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    socketChannel.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
                    socketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                        // channelActive会在连接channel建立成功后,会触发 active事件
                        @Override
                        public void channelActive(ChannelHandlerContext ctx) throws Exception {
                            ByteBuf buffer = ctx.alloc().buffer();
                            Random random = new Random();
                            char ch = 'a';
                            for (int i = 0; i < 10; i++) {
                                for(int j = 0; j < random.nextInt(16) + 1; j++){
                                    buffer.writeByte(ch);
                                }
                                buffer.writeBytes("\n".toString().getBytes());
                                ch++;
                            }
                            ctx.writeAndFlush(buffer);
                        }
                    });
                }
            });
            ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress("localhost", 8080));
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            log.info("clinet error ", e);
        } finally {
            worker.shutdownGracefully();
        }
    }
}

        结果: 

#客户端结果

00:18:56.518 [nioEventLoopGroup-2-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x13d89048, L:/127.0.0.1:61146 - R:localhost/127.0.0.1:8080] WRITE: 71B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 61 61 61 61 61 61 61 61 0a 62 62 62 62 62 62 62 |aaaaaaaa.bbbbbbb|
|00000010| 0a 63 63 63 63 63 0a 64 64 64 64 64 64 64 64 64 |.ccccc.ddddddddd|
|00000020| 64 0a 65 65 65 65 65 0a 66 66 0a 67 67 67 67 67 |d.eeeee.ff.ggggg|
|00000030| 0a 68 68 68 68 68 68 0a 69 69 69 69 69 69 69 0a |.hhhhhh.iiiiiii.|
|00000040| 6a 6a 6a 6a 6a 6a 0a                            |jjjjjj.         |
+--------+-------------------------------------------------+----------------+
00:18:56.518 [nioEventLoopGroup-2-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x13d89048, L:/127.0.0.1:61146 - R:localhost/127.0.0.1:8080] FLUSH


#服务端结果

00:18:56.534 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0xf0a94455, L:/127.0.0.1:8080 - R:/127.0.0.1:61146] READ: 8B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 61 61 61 61 61 61 61 61                         |aaaaaaaa        |
+--------+-------------------------------------------------+----------------+
00:18:56.534 [nioEventLoopGroup-3-1] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded inbound message PooledSlicedByteBuf(ridx: 0, widx: 8, cap: 8/8, unwrapped: PooledUnsafeDirectByteBuf(ridx: 9, widx: 71, cap: 1024)) that reached at the tail of the pipeline. Please check your pipeline configuration.
00:18:56.534 [nioEventLoopGroup-3-1] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded message pipeline : [LineBasedFrameDecoder#0, LoggingHandler#0, DefaultChannelPipeline$TailContext#0]. Channel : [id: 0xf0a94455, L:/127.0.0.1:8080 - R:/127.0.0.1:61146].
00:18:56.534 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0xf0a94455, L:/127.0.0.1:8080 - R:/127.0.0.1:61146] READ: 7B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 62 62 62 62 62 62 62                            |bbbbbbb         |
+--------+-------------------------------------------------+----------------+
00:18:56.534 [nioEventLoopGroup-3-1] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded inbound message PooledSlicedByteBuf(ridx: 0, widx: 7, cap: 7/7, unwrapped: PooledUnsafeDirectByteBuf(ridx: 17, widx: 71, cap: 1024)) that reached at the tail of the pipeline. Please check your pipeline configuration.
00:18:56.534 [nioEventLoopGroup-3-1] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded message pipeline : [LineBasedFrameDecoder#0, LoggingHandler#0, DefaultChannelPipeline$TailContext#0]. Channel : [id: 0xf0a94455, L:/127.0.0.1:8080 - R:/127.0.0.1:61146].
00:18:56.534 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0xf0a94455, L:/127.0.0.1:8080 - R:/127.0.0.1:61146] READ: 5B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 63 63 63 63 63                                  |ccccc           |
+--------+-------------------------------------------------+----------------+

预设长度 

        基于长度的帧解码器:

        使用时需要指定四个长度:

  • lengthFieldOffset:= 1 :偏移量(长度内容所在位置的距离开始处的偏移量的大小)
  • lengthFieldLength:= 2:代表的是标识长度的这个数据所占用的数据长度。
  • lengthAdjustment: = 1:长度内容到具体消息内容的偏移量。
  • initialBytesToStrip:= 3:需要剥离头信息的长度。(是不是需要剥离头,自定)一般我们是要头的。

        使用EmbededChannel编写演示代码

/**
 * 使用EmbededChannel测试LengthFieldDecoder
 */
public class TestLengthFieldDecoder {
    public static void main(String[] args) {
        EmbeddedChannel channel = new EmbeddedChannel(
                new LengthFieldBasedFrameDecoder(
                        1024, 0, 4, 0, 4),
                new LoggingHandler(LogLevel.INFO)
        );
        ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer();
        buildBuffer(buffer, "Hello, world");
        buildBuffer(buffer, "Hi, Hi");
        channel.writeInbound(buffer);
    }

    private static void buildBuffer(ByteBuf buffer, String str) {
        byte[] bytes = str.toString().getBytes();
        int length = bytes.length;
        buffer.writeInt(length);
        buffer.writeBytes(bytes);
    }
}

        结果

00:25:25.154 [main] INFO io.netty.handler.logging.LoggingHandler - [id: 0xembedded, L:embedded - R:embedded] READ: 12B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64             |Hello, world    |
+--------+-------------------------------------------------+----------------+
00:25:25.154 [main] INFO io.netty.handler.logging.LoggingHandler - [id: 0xembedded, L:embedded - R:embedded] READ: 6B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 48 69 2c 20 48 69                               |Hi, Hi          |
+--------+-------------------------------------------------+----------------+
00:25:25.154 [main] INFO io.netty.handler.logging.LoggingHandler - [id: 0xembedded, L:embedded - R:embedded] READ COMPLETE

常见协议代码举例

redis协议

        代码:

/**
 * set name zhangsan
 *  *3
 *  $3
 *  set
 *  $4
 *  name
 *  $8
 *  zhangsan
 */
public class TestRedis {
    final static byte[] LINE = {13, 10};
    public static void main(String[] args) {
        NioEventLoopGroup worker = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(worker);
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
                    ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                        @Override
                        public void channelActive(ChannelHandlerContext ctx) throws Exception {
                            ByteBuf buf = ctx.alloc().buffer();
                            buf.writeBytes("auth 123456".getBytes()).writeBytes(LINE);
                            ctx.writeAndFlush(buf);

                            ByteBuf buffer = ctx.alloc().buffer();
    //                        super.channelInactive(ctx);
                            buffer.writeBytes("*3".getBytes()).writeBytes(LINE);
                            buffer.writeBytes("$3".getBytes()).writeBytes(LINE);
                            buffer.writeBytes("set".getBytes()).writeBytes(LINE);
                            buffer.writeBytes("$4".getBytes()).writeBytes(LINE);
                            buffer.writeBytes("name".getBytes()).writeBytes(LINE);
                            buffer.writeBytes("$8".getBytes()).writeBytes(LINE);
                            buffer.writeBytes("zhangsan".getBytes()).writeBytes(LINE);
                            ctx.writeAndFlush(buffer);
                        }

                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                            ByteBuf buf = (ByteBuf) msg;
                            System.out.println(buf.toString(Charset.defaultCharset()));
                        }
                    });
                }
            });
            ChannelFuture channelFuture = bootstrap.connect("localhost", 6379).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            worker.shutdownGracefully();
        }
    }
}

        结果:

00:27:04.468 [nioEventLoopGroup-2-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x92af23ed, L:/127.0.0.1:62317 - R:localhost/127.0.0.1:6379] WRITE: 13B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 61 75 74 68 20 31 32 33 34 35 36 0d 0a          |auth 123456..   |
+--------+-------------------------------------------------+----------------+
00:27:04.469 [nioEventLoopGroup-2-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x92af23ed, L:/127.0.0.1:62317 - R:localhost/127.0.0.1:6379] FLUSH
00:27:04.469 [nioEventLoopGroup-2-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x92af23ed, L:/127.0.0.1:62317 - R:localhost/127.0.0.1:6379] WRITE: 37B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 2a 33 0d 0a 24 33 0d 0a 73 65 74 0d 0a 24 34 0d |*3..$3..set..$4.|
|00000010| 0a 6e 61 6d 65 0d 0a 24 38 0d 0a 7a 68 61 6e 67 |.name..$8..zhang|
|00000020| 73 61 6e 0d 0a                                  |san..           |
+--------+-------------------------------------------------+----------------+
00:27:04.469 [nioEventLoopGroup-2-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x92af23ed, L:/127.0.0.1:62317 - R:localhost/127.0.0.1:6379] FLUSH
00:27:04.470 [nioEventLoopGroup-2-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x92af23ed, L:/127.0.0.1:62317 - R:localhost/127.0.0.1:6379] READ: 10B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 2b 4f 4b 0d 0a 2b 4f 4b 0d 0a                   |+OK..+OK..      |
+--------+-------------------------------------------------+----------------+
+OK
+OK

00:27:04.470 [nioEventLoopGroup-2-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x92af23ed, L:/127.0.0.1:62317 - R:localhost/127.0.0.1:6379] READ COMPLETE

http协议 

        代码:

@Slf4j
public class TestHttp {
    public static void main(String[] args) {
        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.channel(NioServerSocketChannel.class);
            bootstrap.group(boss, worker);
            bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
                    // Http编解码器
                    ch.pipeline().addLast(new HttpServerCodec());
                    // 入站处理器,可以只关心某一种类型的消息,根据消息的类型进行选择处理
                    ch.pipeline().addLast(new SimpleChannelInboundHandler<HttpRequest>() {
                        @Override
                        protected void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) throws Exception {
                            // 获取请求
                            log.info(msg.uri());
                            // 构建响应
                            DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(msg.protocolVersion(), HttpResponseStatus.OK);
                            byte[] bytes = "<h1>Hello, world</h1>".getBytes();
                            httpResponse.headers().setInt(CONTENT_LENGTH, bytes.length);
                            httpResponse.content().writeBytes(bytes);
                            // 写回响应
                            ctx.writeAndFlush(httpResponse);
                        }




                    });
/*                    ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                            log.info("{}", msg.getClass());
                        }
                    });*/
                }
            });
            ChannelFuture channelFuture = bootstrap.bind(8080).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
//            e.printStackTrace();
            log.error("server error : ", e);
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}

        结果:

00:28:10.860 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x6b07a866, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:55348] READ: 1002B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 47 45 54 20 2f 68 65 6c 6c 6f 20 48 54 54 50 2f |GET /hello HTTP/|
|00000010| 31 2e 31 0d 0a 48 6f 73 74 3a 20 6c 6f 63 61 6c |1.1..Host: local|
|00000020| 68 6f 73 74 3a 38 30 38 30 0d 0a 43 6f 6e 6e 65 |host:8080..Conne|
|00000030| 63 74 69 6f 6e 3a 20 6b 65 65 70 2d 61 6c 69 76 |ction: keep-aliv|
|00000040| 65 0d 0a 73 65 63 2d 63 68 2d 75 61 3a 20 22 4d |e..sec-ch-ua: "M|
|00000050| 69 63 72 6f 73 6f 66 74 20 45 64 67 65 22 3b 76 |icrosoft Edge";v|
|00000060| 3d 22 31 32 35 22 2c 20 22 43 68 72 6f 6d 69 75 |="125", "Chromiu|
|00000070| 6d 22 3b 76 3d 22 31 32 35 22 2c 20 22 4e 6f 74 |m";v="125", "Not|
|00000080| 2e 41 2f 42 72 61 6e 64 22 3b 76 3d 22 32 34 22 |.A/Brand";v="24"|
|00000090| 0d 0a 73 65 63 2d 63 68 2d 75 61 2d 6d 6f 62 69 |..sec-ch-ua-mobi|
|000000a0| 6c 65 3a 20 3f 30 0d 0a 73 65 63 2d 63 68 2d 75 |le: ?0..sec-ch-u|
|000000b0| 61 2d 70 6c 61 74 66 6f 72 6d 3a 20 22 57 69 6e |a-platform: "Win|
|000000c0| 64 6f 77 73 22 0d 0a 55 70 67 72 61 64 65 2d 49 |dows"..Upgrade-I|
|000000d0| 6e 73 65 63 75 72 65 2d 52 65 71 75 65 73 74 73 |nsecure-Requests|
|000000e0| 3a 20 31 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a |: 1..User-Agent:|
|000000f0| 20 4d 6f 7a 69 6c 6c 61 2f 35 2e 30 20 28 57 69 | Mozilla/5.0 (Wi|
|00000100| 6e 64 6f 77 73 20 4e 54 20 31 30 2e 30 3b 20 57 |ndows NT 10.0; W|
|00000110| 69 6e 36 34 3b 20 78 36 34 29 20 41 70 70 6c 65 |in64; x64) Apple|
|00000120| 57 65 62 4b 69 74 2f 35 33 37 2e 33 36 20 28 4b |WebKit/537.36 (K|
|00000130| 48 54 4d 4c 2c 20 6c 69 6b 65 20 47 65 63 6b 6f |HTML, like Gecko|
|00000140| 29 20 43 68 72 6f 6d 65 2f 31 32 35 2e 30 2e 30 |) Chrome/125.0.0|
|00000150| 2e 30 20 53 61 66 61 72 69 2f 35 33 37 2e 33 36 |.0 Safari/537.36|
|00000160| 20 45 64 67 2f 31 32 35 2e 30 2e 30 2e 30 0d 0a | Edg/125.0.0.0..|
|00000170| 41 63 63 65 70 74 3a 20 74 65 78 74 2f 68 74 6d |Accept: text/htm|
|00000180| 6c 2c 61 70 70 6c 69 63 61 74 69 6f 6e 2f 78 68 |l,application/xh|
|00000190| 74 6d 6c 2b 78 6d 6c 2c 61 70 70 6c 69 63 61 74 |tml+xml,applicat|
|000001a0| 69 6f 6e 2f 78 6d 6c 3b 71 3d 30 2e 39 2c 69 6d |ion/xml;q=0.9,im|
|000001b0| 61 67 65 2f 61 76 69 66 2c 69 6d 61 67 65 2f 77 |age/avif,image/w|
|000001c0| 65 62 70 2c 69 6d 61 67 65 2f 61 70 6e 67 2c 2a |ebp,image/apng,*|
|000001d0| 2f 2a 3b 71 3d 30 2e 38 2c 61 70 70 6c 69 63 61 |/*;q=0.8,applica|
|000001e0| 74 69 6f 6e 2f 73 69 67 6e 65 64 2d 65 78 63 68 |tion/signed-exch|
|000001f0| 61 6e 67 65 3b 76 3d 62 33 3b 71 3d 30 2e 37 0d |ange;v=b3;q=0.7.|
|00000200| 0a 53 65 63 2d 46 65 74 63 68 2d 53 69 74 65 3a |.Sec-Fetch-Site:|
|00000210| 20 6e 6f 6e 65 0d 0a 53 65 63 2d 46 65 74 63 68 | none..Sec-Fetch|
|00000220| 2d 4d 6f 64 65 3a 20 6e 61 76 69 67 61 74 65 0d |-Mode: navigate.|
|00000230| 0a 53 65 63 2d 46 65 74 63 68 2d 55 73 65 72 3a |.Sec-Fetch-User:|
|00000240| 20 3f 31 0d 0a 53 65 63 2d 46 65 74 63 68 2d 44 | ?1..Sec-Fetch-D|
|00000250| 65 73 74 3a 20 64 6f 63 75 6d 65 6e 74 0d 0a 41 |est: document..A|
|00000260| 63 63 65 70 74 2d 45 6e 63 6f 64 69 6e 67 3a 20 |ccept-Encoding: |
|00000270| 67 7a 69 70 2c 20 64 65 66 6c 61 74 65 2c 20 62 |gzip, deflate, b|
|00000280| 72 2c 20 7a 73 74 64 0d 0a 41 63 63 65 70 74 2d |r, zstd..Accept-|
|00000290| 4c 61 6e 67 75 61 67 65 3a 20 7a 68 2d 43 4e 2c |Language: zh-CN,|
|000002a0| 7a 68 3b 71 3d 30 2e 39 2c 65 6e 3b 71 3d 30 2e |zh;q=0.9,en;q=0.|
|000002b0| 38 2c 65 6e 2d 47 42 3b 71 3d 30 2e 37 2c 65 6e |8,en-GB;q=0.7,en|
|000002c0| 2d 55 53 3b 71 3d 30 2e 36 0d 0a 43 6f 6f 6b 69 |-US;q=0.6..Cooki|
|000002d0| 65 3a 20 49 64 65 61 2d 39 66 61 62 39 61 62 30 |e: Idea-9fab9ab0|
|000002e0| 3d 35 32 31 66 38 65 33 38 2d 62 34 32 35 2d 34 |=521f8e38-b425-4|
|000002f0| 63 62 36 2d 39 63 39 63 2d 32 61 65 64 31 66 38 |cb6-9c9c-2aed1f8|
|00000300| 64 32 66 38 30 3b 20 58 58 4c 5f 4a 4f 42 5f 4c |d2f80; XXL_JOB_L|
|00000310| 4f 47 49 4e 5f 49 44 45 4e 54 49 54 59 3d 37 62 |OGIN_IDENTITY=7b|
|00000320| 32 32 36 39 36 34 32 32 33 61 33 31 32 63 32 32 |226964223a312c22|
|00000330| 37 35 37 33 36 35 37 32 36 65 36 31 36 64 36 35 |757365726e616d65|
|00000340| 32 32 33 61 32 32 36 31 36 34 36 64 36 39 36 65 |223a2261646d696e|
|00000350| 32 32 32 63 32 32 37 30 36 31 37 33 37 33 37 37 |222c227061737377|
|00000360| 36 66 37 32 36 34 32 32 33 61 32 32 36 35 33 31 |6f7264223a226531|
|00000370| 33 30 36 31 36 34 36 33 33 33 33 39 33 34 33 39 |3061646333393439|
|00000380| 36 32 36 31 33 35 33 39 36 31 36 32 36 32 36 35 |6261353961626265|
|00000390| 33 35 33 36 36 35 33 30 33 35 33 37 36 36 33 32 |3536653035376632|
|000003a0| 33 30 36 36 33 38 33 38 33 33 36 35 32 32 32 63 |306638383365222c|
|000003b0| 32 32 37 32 36 66 36 63 36 35 32 32 33 61 33 31 |22726f6c65223a31|
|000003c0| 32 63 32 32 37 30 36 35 37 32 36 64 36 39 37 33 |2c227065726d6973|
|000003d0| 37 33 36 39 36 66 36 65 32 32 33 61 36 65 37 35 |73696f6e223a6e75|
|000003e0| 36 63 36 63 37 64 0d 0a 0d 0a                   |6c6c7d....      |
+--------+-------------------------------------------------+----------------+
00:28:10.871 [nioEventLoopGroup-3-1] INFO com.example.code.updatenetty.c6http.TestHttp - /hello
00:28:10.874 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x6b07a866, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:55348] WRITE: 60B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d |HTTP/1.1 200 OK.|
|00000010| 0a 63 6f 6e 74 65 6e 74 2d 6c 65 6e 67 74 68 3a |.content-length:|
|00000020| 20 32 31 0d 0a 0d 0a 3c 68 31 3e 48 65 6c 6c 6f | 21....<h1>Hello|
|00000030| 2c 20 77 6f 72 6c 64 3c 2f 68 31 3e             |, world</h1>    |
+--------+-------------------------------------------------+----------------+
00:28:10.875 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x6b07a866, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:55348] FLUSH
00:28:10.875 [nioEventLoopGroup-3-1] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded inbound message EmptyLastHttpContent that reached at the tail of the pipeline. Please check your pipeline configuration.
00:28:10.875 [nioEventLoopGroup-3-1] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded message pipeline : [LoggingHandler#0, HttpServerCodec#0, TestHttp$1$1#0, DefaultChannelPipeline$TailContext#0]. Channel : [id: 0x6b07a866, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:55348].
00:28:10.875 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x6b07a866, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:55348] READ COMPLETE
00:28:10.931 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x6b07a866, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:55348] READ: 928B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 47 45 54 20 2f 66 61 76 69 63 6f 6e 2e 69 63 6f |GET /favicon.ico|
|00000010| 20 48 54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a | HTTP/1.1..Host:|
|00000020| 20 6c 6f 63 61 6c 68 6f 73 74 3a 38 30 38 30 0d | localhost:8080.|
|00000030| 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 6b 65 65 |.Connection: kee|
|00000040| 70 2d 61 6c 69 76 65 0d 0a 73 65 63 2d 63 68 2d |p-alive..sec-ch-|
|00000050| 75 61 3a 20 22 4d 69 63 72 6f 73 6f 66 74 20 45 |ua: "Microsoft E|
|00000060| 64 67 65 22 3b 76 3d 22 31 32 35 22 2c 20 22 43 |dge";v="125", "C|
|00000070| 68 72 6f 6d 69 75 6d 22 3b 76 3d 22 31 32 35 22 |hromium";v="125"|
|00000080| 2c 20 22 4e 6f 74 2e 41 2f 42 72 61 6e 64 22 3b |, "Not.A/Brand";|
|00000090| 76 3d 22 32 34 22 0d 0a 73 65 63 2d 63 68 2d 75 |v="24"..sec-ch-u|
|000000a0| 61 2d 6d 6f 62 69 6c 65 3a 20 3f 30 0d 0a 55 73 |a-mobile: ?0..Us|
|000000b0| 65 72 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c |er-Agent: Mozill|
|000000c0| 61 2f 35 2e 30 20 28 57 69 6e 64 6f 77 73 20 4e |a/5.0 (Windows N|
|000000d0| 54 20 31 30 2e 30 3b 20 57 69 6e 36 34 3b 20 78 |T 10.0; Win64; x|
|000000e0| 36 34 29 20 41 70 70 6c 65 57 65 62 4b 69 74 2f |64) AppleWebKit/|
|000000f0| 35 33 37 2e 33 36 20 28 4b 48 54 4d 4c 2c 20 6c |537.36 (KHTML, l|
|00000100| 69 6b 65 20 47 65 63 6b 6f 29 20 43 68 72 6f 6d |ike Gecko) Chrom|
|00000110| 65 2f 31 32 35 2e 30 2e 30 2e 30 20 53 61 66 61 |e/125.0.0.0 Safa|
|00000120| 72 69 2f 35 33 37 2e 33 36 20 45 64 67 2f 31 32 |ri/537.36 Edg/12|
|00000130| 35 2e 30 2e 30 2e 30 0d 0a 73 65 63 2d 63 68 2d |5.0.0.0..sec-ch-|
|00000140| 75 61 2d 70 6c 61 74 66 6f 72 6d 3a 20 22 57 69 |ua-platform: "Wi|
|00000150| 6e 64 6f 77 73 22 0d 0a 41 63 63 65 70 74 3a 20 |ndows"..Accept: |
|00000160| 69 6d 61 67 65 2f 61 76 69 66 2c 69 6d 61 67 65 |image/avif,image|
|00000170| 2f 77 65 62 70 2c 69 6d 61 67 65 2f 61 70 6e 67 |/webp,image/apng|
|00000180| 2c 69 6d 61 67 65 2f 73 76 67 2b 78 6d 6c 2c 69 |,image/svg+xml,i|
|00000190| 6d 61 67 65 2f 2a 2c 2a 2f 2a 3b 71 3d 30 2e 38 |mage/*,*/*;q=0.8|
|000001a0| 0d 0a 53 65 63 2d 46 65 74 63 68 2d 53 69 74 65 |..Sec-Fetch-Site|
|000001b0| 3a 20 73 61 6d 65 2d 6f 72 69 67 69 6e 0d 0a 53 |: same-origin..S|
|000001c0| 65 63 2d 46 65 74 63 68 2d 4d 6f 64 65 3a 20 6e |ec-Fetch-Mode: n|
|000001d0| 6f 2d 63 6f 72 73 0d 0a 53 65 63 2d 46 65 74 63 |o-cors..Sec-Fetc|
|000001e0| 68 2d 44 65 73 74 3a 20 69 6d 61 67 65 0d 0a 52 |h-Dest: image..R|
|000001f0| 65 66 65 72 65 72 3a 20 68 74 74 70 3a 2f 2f 6c |eferer: http://l|
|00000200| 6f 63 61 6c 68 6f 73 74 3a 38 30 38 30 2f 68 65 |ocalhost:8080/he|
|00000210| 6c 6c 6f 0d 0a 41 63 63 65 70 74 2d 45 6e 63 6f |llo..Accept-Enco|
|00000220| 64 69 6e 67 3a 20 67 7a 69 70 2c 20 64 65 66 6c |ding: gzip, defl|
|00000230| 61 74 65 2c 20 62 72 2c 20 7a 73 74 64 0d 0a 41 |ate, br, zstd..A|
|00000240| 63 63 65 70 74 2d 4c 61 6e 67 75 61 67 65 3a 20 |ccept-Language: |
|00000250| 7a 68 2d 43 4e 2c 7a 68 3b 71 3d 30 2e 39 2c 65 |zh-CN,zh;q=0.9,e|
|00000260| 6e 3b 71 3d 30 2e 38 2c 65 6e 2d 47 42 3b 71 3d |n;q=0.8,en-GB;q=|
|00000270| 30 2e 37 2c 65 6e 2d 55 53 3b 71 3d 30 2e 36 0d |0.7,en-US;q=0.6.|
|00000280| 0a 43 6f 6f 6b 69 65 3a 20 49 64 65 61 2d 39 66 |.Cookie: Idea-9f|
|00000290| 61 62 39 61 62 30 3d 35 32 31 66 38 65 33 38 2d |ab9ab0=521f8e38-|
|000002a0| 62 34 32 35 2d 34 63 62 36 2d 39 63 39 63 2d 32 |b425-4cb6-9c9c-2|
|000002b0| 61 65 64 31 66 38 64 32 66 38 30 3b 20 58 58 4c |aed1f8d2f80; XXL|
|000002c0| 5f 4a 4f 42 5f 4c 4f 47 49 4e 5f 49 44 45 4e 54 |_JOB_LOGIN_IDENT|
|000002d0| 49 54 59 3d 37 62 32 32 36 39 36 34 32 32 33 61 |ITY=7b226964223a|
|000002e0| 33 31 32 63 32 32 37 35 37 33 36 35 37 32 36 65 |312c22757365726e|
|000002f0| 36 31 36 64 36 35 32 32 33 61 32 32 36 31 36 34 |616d65223a226164|
|00000300| 36 64 36 39 36 65 32 32 32 63 32 32 37 30 36 31 |6d696e222c227061|
|00000310| 37 33 37 33 37 37 36 66 37 32 36 34 32 32 33 61 |7373776f7264223a|
|00000320| 32 32 36 35 33 31 33 30 36 31 36 34 36 33 33 33 |2265313061646333|
|00000330| 33 39 33 34 33 39 36 32 36 31 33 35 33 39 36 31 |3934396261353961|
|00000340| 36 32 36 32 36 35 33 35 33 36 36 35 33 30 33 35 |6262653536653035|
|00000350| 33 37 36 36 33 32 33 30 36 36 33 38 33 38 33 33 |3766323066383833|
|00000360| 36 35 32 32 32 63 32 32 37 32 36 66 36 63 36 35 |65222c22726f6c65|
|00000370| 32 32 33 61 33 31 32 63 32 32 37 30 36 35 37 32 |223a312c22706572|
|00000380| 36 64 36 39 37 33 37 33 36 39 36 66 36 65 32 32 |6d697373696f6e22|
|00000390| 33 61 36 65 37 35 36 63 36 63 37 64 0d 0a 0d 0a |3a6e756c6c7d....|
+--------+-------------------------------------------------+----------------+
00:28:10.931 [nioEventLoopGroup-3-1] INFO com.example.code.updatenetty.c6http.TestHttp - /favicon.ico
00:28:10.931 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x6b07a866, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:55348] WRITE: 60B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d |HTTP/1.1 200 OK.|
|00000010| 0a 63 6f 6e 74 65 6e 74 2d 6c 65 6e 67 74 68 3a |.content-length:|
|00000020| 20 32 31 0d 0a 0d 0a 3c 68 31 3e 48 65 6c 6c 6f | 21....<h1>Hello|
|00000030| 2c 20 77 6f 72 6c 64 3c 2f 68 31 3e             |, world</h1>    |
+--------+-------------------------------------------------+----------------+
00:28:10.932 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x6b07a866, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:55348] FLUSH
00:28:10.932 [nioEventLoopGroup-3-1] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded inbound message EmptyLastHttpContent that reached at the tail of the pipeline. Please check your pipeline configuration.
00:28:10.932 [nioEventLoopGroup-3-1] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded message pipeline : [LoggingHandler#0, HttpServerCodec#0, TestHttp$1$1#0, DefaultChannelPipeline$TailContext#0]. Channel : [id: 0x6b07a866, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:55348].
00:28:10.932 [nioEventLoopGroup-3-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x6b07a866, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:55348] READ COMPLETE

 参考链接

Netty使用篇:半包&粘包_netty 半包粘包-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/667280.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

BearPi-HM Nano开发笔记

小熊派 简单介绍 BearPi-HM Nano开发板是一块专门为鸿蒙OS设计的HarmonyOS开发板&#xff0c;板载高度集成的2.4GHz WLAN SoC芯片Hi3861&#xff0c;并板载NFC电路及标准的E53接口可拓展 E53接口 介绍 E53接口标准为“物联网俱乐部”联合国内多家开发板厂家制定的物联网案…

QT天气预报项目(写在简历上)

一、ui设计 实现功能:可以搜索不同的城市进行天气的查询,并且显示未来7天内的天气,并绘制出当天的最高气温和最低气温曲线图。 学到的知识: stylesheet界面美化 Json数据解析 HTTP通信get请求 使用事件过滤器绘制温度曲线 多控件处理(利用数组) 代码整合调试能力 二…

Debian和ubuntu 嵌入式的系统的 区别

随着开源操作系统的日益流行&#xff0c;Debian和Ubuntu这两个基于Linux的发行版本成为了众多开发者和系统管理员的首选。它们各自拥有独特的优势和特点&#xff0c;那么&#xff0c;在选择时&#xff0c;哪一个更适合你呢&#xff1f;接下来&#xff0c;我们将深入探讨两者的关…

软件设计不是CRUD(21):在流式数据处理系统中进行业务抽象落地——需求分析

本文主要介绍如何在数据处理系统中应用业务抽象的设计思想。目前业界流行的数据处理方式是流式处理&#xff0c;主流的流式处理引擎有Apache Spark&#xff0c;Apache Flink等等。本文选择Apache Flink作为实战案例的落地。由于本文主要是讲解设计思想和流式处理引擎相结合的方…

ETLCloud中如何使用Kettle组件

ETLCloud中如何使用Kettle组件在当今数据驱动的时代&#xff0c;数据处理和分析已成为企业决策的关键。为了更高效地处理海量数据&#xff0c;ETL&#xff08;Extract, Transform, Load&#xff09;工具变得至关重要。而在众多ETL工具中&#xff0c;Kettle作为一款开源、灵活且…

深入分析 Android Service (五)

文章目录 深入分析 Android Service (五)1. 深入分析 Service 与 Activity 之间的通信2. Messenger 的内部工作原理2.1 服务端实现2.2 客户端实现 3. AIDL 的内部工作原理3.1 定义 AIDL 接口3.2 服务端实现3.3 客户端实现 4. Service 的优化建议和最佳实践4.1 异步操作4.2 资源…

基于STM32的轻量级Web服务器设计

文章目录 一、前言1.1 开发背景1.2 实现的功能1.3 硬件模块组成1.4 ENC28J60网卡介绍1.5 UIP协议栈【1】目标与特点【2】核心组件【3】应用与优势 1.6 添加UIP协议栈实现创建WEB服务器步骤1.7 ENC28J60添加UIP协议栈实现创建WEB客户端1.8 ENC28J60移植UIP协议并编写服务器测试示…

关于亚马逊、速卖通、虾皮、Lazada等平台自养号测评IP的重要性

在自养号测评中&#xff0c;IP的纯净度是一个至关重要的问题&#xff0c;它直接关系到账号的安全性和稳定性如果使用了被平台识别为异常或存在风险的IP地址&#xff0c;那么账号可能会面临被封禁的风险。这将对账号的正常使用和测评过程中造成严重影响。而使用纯净的IP地址&…

用万界星空科技低代码平台能快速搭建一个云MES系统

一、低代码平台与MES:智能制造的新篇章 随着工业4.0和智能制造的兴起&#xff0c;企业对于生产过程的数字化、智能化需求日益迫切。传统的MES系统实施周期长、成本高&#xff0c;成为许多企业数字化转型的瓶颈。而低代码开发平台的出现为这一问题提供了新的解决思路。 二、万界…

数据库(12)——DQL聚合查询

常见的聚合函数 将一列数据作为一个整体&#xff0c;进行纵向计算。 函数功能count统计数量max最大值min最小值avg平均值sum求和 语法 SELECT 聚合函数 &#xff08;字段列表&#xff09;FROM 表名; 示例 这是我们的原始表&#xff1a; 求人物总数 select count(id) from in…

HTML静态网页成品作业(HTML+CSS)—— 冶金工程专业展望与介绍介绍网页(2个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有2个页面。 二、作品演示 三、代…

容器技术基础理论与常用命令:必知必会,效率翻倍!

如何利用容器技术提升你的工作效率&#xff1f;掌握基础理论和常用命令是必不可少的&#xff0c;本文将为你全面介绍容器技术&#xff0c;并教你必知必会的技能&#xff0c;让你工作、学习效率翻倍&#xff0c;对于网络安全工作者也是必不可少的技能&#xff01; 0. 引言 学习…

【WEEK14】 【DAY3】Swagger第一部分【中文版】

2024.5.29 Wednesday 目录 16.Swagger16.1.Swagger简介16.1.1.前后端分离16.1.2.前后端分离时代16.1.3.产生的问题16.1.4.解决方案16.1.5.Swagger 16.2.SpringBoot集成Swagger16.2.1.新建swagger-demo项目16.2.2.导入依赖16.2.2.1.springfox-swagger216.2.2.2.springfox-swagge…

linux部署运维1——centos7.9离线安装部署涛思taos2.6时序数据库TDengine

在实际项目开发过程中&#xff0c;并非一直都使用关系型数据库&#xff0c;对于工业互联网类型的项目来说&#xff0c;时序型数据库也是很重要的一种&#xff0c;因此掌握时序数据库的安装配置也是必要的技能&#xff0c;不过对于有关系型数据库使用的开发工作者来说&#xff0…

python-模块-网络编程-多任务

一、模块 1-1 Python 自带模块 Json模块 处理json数据 {"key":"value"} json不是字典 本质是一个有引号的字符串数据 json注意点 {} 中的数据是字符串引号必须是双引号 使用json模块可以实现将json转为字典&#xff0c;使用字典的方法操作数据 。 或者将…

【为什么 Google Chrome 打开网页有时极慢?尤其是国内网站,如知网等】

要通过知网搜一点资料&#xff0c;发现怎么都打不开。而且B站&#xff0c;知乎这些速度也变慢了&#xff01;已经检查过确定不是网络的问题。 清空了记录&#xff0c;清空了已接受Cookie&#xff0c;清空了缓存内容……没用&#xff01;&#xff01;&#xff01; 不断搜索&am…

3D模型太大转换为线形3d渲染中为什么显示不出来?---模大狮模型网

在3D设计和渲染过程中&#xff0c;有时会遇到模型过大的情况&#xff0c;为了提高软件的响应速度和工作效率&#xff0c;将模型转换为线性模式是一种常见的解决方法。然而&#xff0c;有时在转换为线性模式后&#xff0c;可能会出现模型无法显示的问题。本文将探讨在3D渲染中将…

3、css3 手写nav导航条(互相学习)

效果例图&#xff1a; 1、首先呈现的是html代码&#xff1a; <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><…

LabVIEW车体静强度试验台测控系统

LabVIEW车体静强度试验台测控系统 开发了一种基于LabVIEW的车体静强度试验台测控系统&#xff0c;通过自动化技术提高试验的精度和效率。系统采用LabVIEW软件与S7-200 SMART PLC硬件平台相结合&#xff0c;实现了对液压缸作用力的精确控制和试验数据的实时采集及管理。 传统的…

高德地图 JS API用于绘画船舶轨迹

文章目录 引言I 2.0升级指南1.1 修改 JSAPI 引用中的版本号到 2.01.2 相应修改II 1.4.15 文档引言 地图 JS API 2.0 是高德开放平台免费提供的第四代 Web 地图渲染引擎, 以 WebGL 为主要绘图手段,本着“更轻、更快、更易用”的服务原则,广泛采用了各种前沿技术,交互体验、…