zoukankan      html  css  js  c++  java
  • Netty(三、拆包粘包)

    拆包粘包

    TCP在向目标发送数据时,会通过缓冲区发送,当数据达不到缓冲区的大小时会发生粘包。当数据超过缓冲区大小时,则会分成多个部分,就是拆包。

     例如上图:我们实际发送和希望接收到这样的数据,但是实际却有可能接收成这样。

    程序中,我们这样向服务器发送三条数据,而服务端只接收到一条:

     

     Netty解决方案

    DelimiterBasedFrameDecoder

    通过自定义分隔符实现拆包粘包

    服务端:

    //5.配发事件处理器流水线
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            String delimiter = "_$";
                            //定义拆包粘包的解码器
                            socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, Unpooled.wrappedBuffer(delimiter.getBytes())));
                            //解码器
                            socketChannel.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
                            //编码器
                            socketChannel.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
                            //自定义的编码器,输出信息后面加上分隔符
                            socketChannel.pipeline().addLast(new DelimiterBasedFrameEncoder(delimiter));
                            //自定义事件处理器
                            socketChannel.pipeline().addLast(new NettyServerHandler());
    
    
                        }
                    });

    自定义:DelimiterBasedFrameEncoder

    package com.wk.test.nettyTest;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelHandler;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.handler.codec.MessageToByteEncoder;
    @ChannelHandler.Sharable
    public class DelimiterBasedFrameEncoder extends MessageToByteEncoder<String> {
    
        private String delimiter;
    
        public DelimiterBasedFrameEncoder(String delimiter){
            this.delimiter = delimiter;
        }
    
        @Override
        protected void encode(ChannelHandlerContext channelHandlerContext, String message, ByteBuf byteBuf) throws Exception {
            channelHandlerContext.writeAndFlush(Unpooled.wrappedBuffer((message + delimiter).getBytes()));
        }
    
    }

    客户端:

    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            String delimiter = "_$";
                            socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, Unpooled.wrappedBuffer(delimiter.getBytes())));
                            //解码器
                            socketChannel.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
                            //编码器
                            socketChannel.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
                            socketChannel.pipeline().addLast(new DelimiterBasedFrameEncoder(delimiter));
                            socketChannel.pipeline().addLast(new NettyClientHandler());
                        }
                    });

    这里只列举这种方法,还有其他方法如固定解码长度等,这里不一一列举。

  • 相关阅读:
    数据库原理分析
    数据库常见索引解析(B树,B-树,B+树,B*树,位图索引,Hash索引)
    数据库索引、B树、B+树
    列存储索引
    比较全面的gdb调试命令
    SQLSERVER如何查看索引缺失
    VIM 实现tab标签页及分屏,切换命令
    查看指定spid的脚本当前运行情况和状态
    通过 sysprocesses 简单查询死锁及解决死锁办法
    ASP.NET Core开源地址
  • 原文地址:https://www.cnblogs.com/Unlimited-Blade-Works/p/12699932.html
Copyright © 2011-2022 走看看