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

news2025/1/18 16:45:21

目录

粘包、半包

相关概念

网络数据发送和接收过程

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博客

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

input输入框的一些复习

<template><div><div style"text-align: center;margin: 10px 0;"><span style"font-size: 15px;font-weight: bold;">input输入框的基本应用</span></div><el-descriptions :column"3" size"defau…

Golang dlv远程debug

1. 前期准备 1.1. dlv安装 1.1.1. go install安装 go install github.com/go-delve/delve/cmd/dlvlatest1.1.2. 手动安装 下载 linuxx86 架构 二进制文件 &#x1f4ce;dlv.linux.x86.zip zip文件&#xff0c;下载后&#xff08; 如果没权限&#xff0c;记得 执行chmod ax…

linux下使用cmake-gui编译WXQT

一.编译环境 操作系统&#xff1a;Ubuntu 22.04.3 LTS wxWidgets源码&#xff1a;wxWidgets-3.1.5 编译工具&#xff1a;CMake-gui qt版本&#xff1a;5.13.2 二.编译步骤 1.将源码解压。 2.打开CMake-gui&#xff0c;并设置好源码目录和构建目录 3.点击configure 会弹出…

【c++入门】this指针

this指针引出&#xff1a; 我们知道一个类可以有多个实例化对象&#xff0c;但是这多个实例化对象所调用的成员函数是在公共代码区&#xff1b; 我们先来定义一个Date类&#xff1a; class Date { public:void init(int year, int month, int day){_year year;_month month;…

excel怎么对非数字求和汇总?

如&#xff1a;学生小王的成绩为&#xff1a;A&#xff0c;A&#xff0c;A&#xff0c;A&#xff0c;B&#xff0c;B-……想得到的成绩汇总求和为&#xff1a;2A,2A,1B,1B- 如果在低版本里&#xff0c;用公式计算可能相当复杂&#xff0c;但是有了TEXTJOIN函数和UNIQUE函数&…

一、实现一个简单的 Google Chrome 扩展程序

目录 &#x1f9ed; 效果展示 # 图示效果 a. 拓展程序列表图示效果&#xff1a; b. 当前选项卡页面右键效果&#xff1a; c. 拓展程序消息提示效果&#xff1a; &#x1f4c7; 项目目录结构 # 说明 # 结构 # 文件一览 ✍ 核心代码 # manifest.json # background.j…

数据结构算法 数组的实现与练习(C语言实现,Java实现)

文章目录 数据结构数组(顺序表)特点使用Java实现更高级的数组C语言实现总结优点缺点 例题[26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/)[1. 两数之和](https://leetcode.cn/problems/two-sum/)[27. 移除元素](https://lee…

阿里云部署nodejs

目录 1、安装node.js 1-1 进入opt/software 1-2 下载node.js安装包 1-3 解压 2 配置环境变量 2-1 vim中配置环境变量 2-2 命令行中保存环境变量 2-3 检查安装版本 2-3 更换镜像 3、上传node.js项目 1-1 启动项目 1-2 配置对应的安全组 ​编辑 4、pm2启动多个node项…

Scroll 上的明星项目Pencils Protocol ,缘何被严重低估?

近日&#xff0c;完成品牌升级的 Pencils Prtocol 结束了 Season 2 并无缝开启了 Season 3&#xff0c;在 Season 3 中&#xff0c;用户可以通过质押系列资产包括 $ETH、$USDT、$USDC、$STONE 、$wrsETH、$pufETH 等来获得可观收益&#xff0c;并获得包括 Scroll Marks、 Penci…

二叉树的前序遍历(oj题)

一、题目链接&#xff1a; https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ 二、题目思路 先调用二叉树节点计算函数&#xff0c;得到二叉树的总结点数。然后申请该大小的数组空间。 再使用前序遍历&#xff0c;依次访问每个结点的数据&#xff0c;依次存…

01-1.2.3 算法的空间复杂度

什么是空间复杂度&#xff1f; 代码在运行之前需要先装入内存&#xff0c;程序代码需要占一定的位置&#xff08;在这边假设是100B&#xff09; 定义的变量和参数i&#xff0c;n都需要占用内存空间 //算法一——逐步递增型 void loveYou(int n) { //n为问题规模int i 1; /…

Notepad++ 常用

File Edit search view Encoding Language Settings Tools Macro Run Plugins Window 文件 编辑 搜索 视图 编码 语言 设置 工具 宏 运行 插件 窗口 快捷方式 定位行 &#xff1a;CTRL g查找&#xff1a; CTRL F替换&am…

未来已来, AI将作为超级工具?

人工智能时代已来 1.AI将作为超级工具&#xff1a;AI是推动全产业数字化转型的高效工具&#xff0c;机遇比互联网时代大10倍&#xff0c;但只有1/3的机会留给初创企业。 2.硅谷AI市场分类中&#xff0c;特别看好开源平台&#xff0c;其将为初创企业和大企业提供更多选择。 3.…

LabVIEW调用外部DLL(动态链接库)

LabVIEW调用外部DLL&#xff08;动态链接库&#xff09; LabVIEW调用外部DLL&#xff08;动态链接库&#xff09;可以扩展其功能&#xff0c;使用外部库实现复杂计算、硬件控制等任务。通过调用节点&#xff08;Call Library Function Node&#xff09;配置DLL路径、函数名称和…

chatMed开发日志博客(持续更新中)

目录 1. 项目概述 2. 开发人员团队 3. 大致需求 4. 开发内容 4.1. 前端开发 4.1.1: 前端页面开发 4.1.2: 登录机制以及路由守卫的开发 4.1.3: 文件上传机制和保存机制 4.1.4: 消息传递机制 4.2. 线程池开发 4.3. 在线调试 1. 项目概述 搭建一个基于深度学习的分析平台…

Scrapy vs. Beautiful Soup | 网络抓取教程 2024

网络爬虫是任何想要从网上收集数据用于分析、研究或商业智能的人必备的技能。Python中两个最受欢迎的网络爬虫工具是Scrapy和Beautiful Soup。在本教程中&#xff0c;我们将比较这些工具&#xff0c;探索它们的功能&#xff0c;并指导你如何有效地使用它们。此外&#xff0c;我…

国产FPGA核心板!米尔紫光同创Logos-2和Xilinx Artix-7核心板

随着嵌入式的快速发展&#xff0c;在工控、通信、5G通信领域&#xff0c;FPGA以其超灵活的可编程能力&#xff0c;被越来越多的工程师选择。近日&#xff0c;米尔电子发布2款FPGA的核心板和开发板&#xff0c;型号分别为&#xff1a;基于紫光同创Logos-2系列PG2L100H的MYC-J2L1…

Linux基础指令及其作用之系统信息和管理

系统信息和管理 ps ps 命令用于显示当前系统的进程信息。它是 Unix 和类 Unix 操作系统中的一个重要工具&#xff0c;可以用于监控和管理系统进程。以下是 ps 命令的详细用法和常见选项&#xff1a; ps [选项]常用选项![在这里插入图片描述](https://img-blog.csdnimg.cn/di…

从摇一摇到弹窗,AD无处不在?为了不再受打扰,推荐几款好用的屏蔽软件,让手机电脑更清爽

当我们沉浸在智能手机带来的便捷与乐趣中时&#xff0c;内置AD如同不速之客&#xff0c;时常打断我们的体验。 尤其是手机上那些“摇一摇”跳转&#xff0c;稍有不慎就会跳转到其他应用&#xff0c;令人不胜其烦。同样&#xff0c;电脑上的内置AD也如影随形&#xff0c;影响了我…

深度学习模型的C++部署:ONNXRUNTIME引领跨平台革命

一、引言 在AI技术的浪潮中&#xff0c;深度学习模型的部署已成为工程师们的核心技能。随着AI技术的不断进步&#xff0c;对于能够高效部署模型的人才需求日益增长。C因其在性能和系统级控制方面的优势&#xff0c;正逐渐成为深度学习模型部署的行业新宠。 二、C&#xff1a;…