• netty学习


    NIO(非阻塞IO):Selector、ByteBuffer、Channel

    三大组件

    • Channel & Buffer
      Channel类似Stream,是读写数据的双向通道,可以从Channel将数据读入Buffer,也可以将Buffer的数据写入Channel,常见的Channel(FileChannel、DatagramChannel(udp)、SocketChannel、ServerSocketChannel)。Buffer用来缓冲读写数据,常见Buffer(ByteBuffer、ShrotBuffer、IntBuffer、LongBuffer。。。)。
    • Selector
      多线程模板下的缺点:内存占用高、线程上下文切换成本高、只适合连接数少的场景。
      线程池模板下的缺点:阻塞模式下,线程只能处理一个Socket连接、仅适合短连接场景。
      Selector模板下:Selector的作用就是配合一个线程来管理多个Channel,获取这些Channel上发生的事件,这些Channel工作在非阻塞模式下,线程不会阻塞在一个Channel上,适合连接数特别多,但流量低的场景。调用Selector的select()会阻塞直到Channel发生了读写就绪事件,并交给线程来处理。
    • ByteBuffer
    try(FileChannel channel = new FileInputStream(data.txt).getChannel()) {
        // 缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(10);
        while(true) {
            // 从channel读取数据,向buffer写入
            int len = channel.read(buffer);
            if(len == -1) { 
                break;        
            }
            //切换至读模式
            buffer.flip();
            // 是否还有剩余未读数据
            while(buffer.hasRemaining()) {
                byte b = buffer.get();
                System.out.println((char) b);
            }
            //切换至写模式
            buffer.clear(); // compact()
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    结构:capaticy(buffer容量)、position(写入位置,指针)、limit(写入限制)
    在这里插入图片描述
    在这里插入图片描述

    • 常用方法
      分配空间:allocate()
      写入数据:channel.read(buffer), buffer.put()
      读取数据:channel.write(buffer), buffer.get()
      rewind()、mark()、reset()、get(i)
    • 字符串与ByteBuffer转换
    // 字符串转ByteBuffer
    ByteBuffer buffer = ByteBuffer.allocate(16);
    buffer.put("hello".getBytes());
    
    // 使用Charset,会直接切换到读模式
    ByteBuffer buffer = StandardCharsets.UTF_8.encode("hello")
    
    // wrap
    ByteBuffer buffer = ByteBuffer.wrap("hello".getBytes());
    
    // 转String
    String str = StandardCharsets.UTF_8.decode(buffer).toString()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 黏包半包
      数据在传输过程中由于某种原因进行了重新组合
      发送:
      Hello,world\n
      I’m zhangsan\n
      How are you\n
      接收:(黏包半包) 缓冲区大小问题
      Hello,world\nI’m zhangsan\nHo
      w are you\n
    private static void split(ByteBuffer source) {
        // 读模式
        source.flip();
        for (int i = 0; i < source.limit(); i++) {
            // 匹配到完整信息
            if (source.get(i) == '\n') {
                // 获取完整信息长度
                int length = i + 1 - source.position();
                ByteBuffer target = ByteBuffer.allocate(length);
                for (int j = 0; j < length; j++) {
                    // 插入数据,更新position位置
                    target.put(source.get());
                }
            }
        }
        // 将半包状态下未读完数据移到前面
        source.compact();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    SQL注入 基础学习
    九、MyBatis的缓存
    13.5 GAS与连击
    “乘风破浪”的芒果超媒,能上岸吗?
    通过Redis实现一个异步请求-响应程序
    基于51单片机的气泵气压控制系统无线WiFi通信proteus仿真原理图PCB
    【晶振专题】案例:为什么对着STM32低速32.768K晶振哈口气就不起振了?
    设计和前端相关工具
    如何把网站的http改成https?
    【生日快乐】SpringBoot SpringBoot 基础篇(第一篇) 第4章 SpringBoot 综合案例 4.8 删除客户
  • 原文地址:https://blog.csdn.net/gltncx11/article/details/125453210