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());
                        }
                    });

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

  • 相关阅读:
    关于自链接的视图的更新
    JavaScript局部变量与全局变量2
    减少IDE中的新建项
    whitespace对select无效
    学习摘录21
    让我记得写文档的设置
    本地连接不见了
    jquery 学习笔记
    jquery用load引入页面
    android笔记
  • 原文地址:https://www.cnblogs.com/Unlimited-Blade-Works/p/12699932.html
Copyright © 2011-2022 走看看