• netty 拆包/粘包



    netty 通信框架性能怪兽

    当你了:

    1. 解了阻塞模型

    2. 非阻塞模型

    3. react模型
      知道这些原理之后,你不得不惊叹于netty的设计

      selector 多路复用: 单线程可以配合 Selector 完成对多个 Channel 可读写事件的监控,这称之为多路复用;
      0拷贝:splice函数的作用是将两个文件描述符之间建立一个管道,然后将文件描述符的引用传递过去,这样在使用到数据的时候就可以直接通过引用指针访问到具体数据,之前是拷贝数据,现在变为了传递映射指针,然后直接访问到数据;
      缓冲区 :我认为缓冲区是netty提升性能的基础,有了缓冲区,才能实现多路复用,缓冲区相当于是netty传递消息的载体,贯穿整个netty;

    随便拿出来一个都能吊打各路高手,netty集万千高级思想于一身


    一、什么是拆包 粘包?

    这要从TCP协议,缓冲区说起了;

    • 发送方发送的消息较大,在传输之前会被 TCP 底层拆分,这个过程称为拆包;
    • 接收方接受消息的时候, 会将多个小的消息变为一个包,这个合并的过程称为粘包;
    • 当然可能同时存在拆包和粘包,例如接受到的消息为两部分组成(A B), 一部分是一个A的全部,另一个部分为B的一部分,这就是既有拆包又有粘包;

    这里面 缓冲区就是在传输过程中的一个缓冲的地方,他如果很大, 他就会讲小的消息体整合发送,他如果很小,就会将一个完整的消息体拆分下,然后发送;

    二、拆包 粘包的弊端

    会导致消息解析出现问题, 因为可能接受的消息不完整,也可能接受的消息是两部分,导致接受到后无法正确解析语义;

    三、netty的解决方案

    1. LineBasedFrameDecoder 行拆包 以换行符作为分隔符
    2. DelimiterBasedFrameDecoder 指定分隔符 以自定义的分隔符作为 消息结束标志
    3. LengthFieldBasedFrameDecoder 基于数据包长度的拆包 将应用层数据包的长度固定
    4. MessageToByteEncoder和 ByteToMessageDecoder 自定义粘包拆包器

    比较常见的就是DelimiterBasedFrameDecoder 用此种方式实现

    用自定义分隔符作为一个消息的结束,解析即可

    bootstrap.group(parentGroup, childGroup)
             .channel(NioServerSocketChannel.class)
             .option(ChannelOption.SO_BACKLOG, 1024)
            //接收套接字缓冲区大小
            .option(ChannelOption.SO_RCVBUF, 1024 * 1024)
            //发送套接字缓冲区大小
            .option(ChannelOption.SO_SNDBUF, 1024 * 1024)
            .option(ChannelOption.SO_KEEPALIVE, true)
            .option(ChannelOption.TCP_NODELAY, true)
            .handler(new LoggingHandler(LogLevel.INFO))
    		.childHandler(new ChannelInitializer<SocketChannel>() {
    
    	    @Override
    	    protected void initChannel(SocketChannel ch) throws Exception {
    	        ChannelPipeline pipeline = ch.pipeline();
    	        // 这里将FixedLengthFrameDecoder添加到pipeline中,指定长度为100
    	        // pipeline.addLast(new FixedLengthFrameDecoder(100));
    	        //这里将LineBasedFrameDecoder添加到pipeline中,设置最大长度为1024
    	        // pipeline.addLast(new LineBasedFrameDecoder(1024));
    	
    	        //被按照$_$进行分隔,这里1024指的是分隔的最大长度,即当读取到1024个字节的数据之后,
    	        // 若还是未读取到分隔符,则舍弃当前数据段,因为其很有可能是由于码流紊乱造成的
    	        ByteBuf delimiter = copiedBuffer(Constants.MESSAGE_DELIMITER.getBytes(Charset.forName("UTF-8")));
    	        ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
    	
    	        // StringEncoder:字符串编码器,将String编码为将要发送到Channel中的ByteBuf
    	        pipeline.addLast(new StringEncoder(Charset.forName("UTF-8")));
    	        // StringDecoder:字符串解码器,将Channel中的ByteBuf数据解码为String
    	        pipeline.addLast(new StringDecoder(Charset.forName("UTF-8")));
    	        //绑定处理器(可绑定多个)
    	        pipeline.addLast(new ServerHandler()); //处理业务
    	    }
    	});
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    作为解析方,只需要根据分隔符作为消息分割即可,然后就能正确解析消息了;


    总结

    netty真的是网络通讯中的王者,很多优秀的RPC框架,通讯等,底层都是采用netty作为通讯手段,之后还会写几篇netty的文章;

  • 相关阅读:
    Dubbo 2.6.1升级
    电工三级证(高级)实战项目:PLC控制三相异步电动机的Y-Δ星三角降压启动
    redis基础3——配置文件核心参数实测+RDB持久化、AOF持久化核心参数详解
    猿创征文|前端安全(XSS和CSRF)
    一分钟带你了解网页升级访问原因
    数据结构 图
    Mycat2.0搭建教程
    会议高清直播录播系统
    ROS1云课→01简介和配置
    js控制台输出佛祖保佑图形图案/彩色图形图案实例代码
  • 原文地址:https://blog.csdn.net/qq_32419139/article/details/132346178