• 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
  • 相关阅读:
    AIGC实战——基于Transformer实现音乐生成
    基于51单片机八路电压表采集系统波形发生器
    Python自学笔记9:实操案例六(千年虫,购物流程)
    申请专利的好处!这份清单告诉你,为什么要申请专利?
    并发-生产者消费者、线上问题定位、性能测试、异步任务池
    #django基本常识01#
    数据库原理课程设计
    vscode连接服务器步骤
    react-native渲染富文本的几种方案
    Python基础语法速成1
  • 原文地址:https://blog.csdn.net/gltncx11/article/details/125453210