小工具知识网

当前位置: 首页 > 行业知识 > Netty(1)nio

行业知识

Netty(1)nio

2026-11-13 02:38:26 来源:互联网转载

一. NIO 基础

non-blocking io 非阻塞 IO

1. 三大组件

1.1 Channel & Buffer

channel 有一点类似于 stream,它就是读写数据的双向通道,可以从 channel 将数据读入 buffer,也可以将 buffer 的数据写入 channel,而之前的 stream 要么是输入,要么是输出,channel 比 stream 更为底层

常见的 Channel 有

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel

    buffer 则用来缓冲读写数据,常见的 buffer 有

    • ByteBuffer
      • MappedByteBuffer
      • DirectByteBuffer
      • HeapByteBuffer
      • ShortBuffer
      • IntBuffer
      • LongBuffer
      • FloatBuffer
      • DoubleBuffer
      • CharBuffer

        1.2 Selector

        selector 单从字面意思不好理解,需要结合服务器的设计演化来理解它的用途

        多线程版设计
        ⚠️ 多线程版缺点
        • 内存占用高
        • 线程上下文切换成本高
        • 只适合连接数少的场景
          线程池版设计
          ⚠️ 线程池版缺点
          • 阻塞模式下,线程仅能处理一个 socket 连接
          • 仅适合短连接场景
            selector 版设计

            selector 的作用就是配合一个线程来管理多个 channel,获取这些 channel 上发生的事件,这些 channel 工作在非阻塞模式下,不会让线程吊***在一个 channel 上。适合连接数特别多,但流量低的场景(low traffic)

            调用 selector 的 select() 会阻塞直到 channel 发生了读写就绪事件,这些事件发生,select 方法就会返回这些事件交给 thread 来处理

            2. ByteBuffer

            有一普通文本文件 data.txt,内容为

            1234567890abcd

            使用 FileChannel 来读取文件内容

            @Slf4jpublic class ChannelDemo1 {    public static void main(String[] args) {        try (RandomAccessFile file = new RandomAccessFile("helloword/data.txt", "rw")) {            FileChannel channel = file.getChannel();            ByteBuffer buffer = ByteBuffer.allocate(10);            do {                // 向 buffer 写入                int len = channel.read(buffer);                log.debug("读到字节数:{}", len);                if (len == -1) {                    break;                }                // 切换 buffer 读模式                buffer.flip();                while(buffer.hasRemaining()) {                    log.debug("{}", (char)buffer.get());                }                // 切换 buffer 写模式                buffer.clear();            } while (true);        } catch (IOException e) {            e.printStackTrace();        }    }}

            输出

            10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 读到字节数:1010:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 110:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 210:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 310:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 410:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 510:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 610:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 710:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 810:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 910:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 010:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 读到字节数:410:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - a10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - b10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - c10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - d10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 读到字节数:-1

            2.1 ByteBuffer 正确使用姿势

            1. 向 buffer 写入数据,例如调用 channel.read(buffer)
            2. 调用 flip() 切换至读模式
            3. 从 buffer 读取数据,例如调用 buffer.get()
            4. 调用 clear() 或 compact() 切换至写模式
            5. 重复 1~4 步骤

            2.2 ByteBuffer 结构

            ByteBuffer 有以下重要属性

            • capacity
            • position
            • limit

              一开始

              写模式下,position 是写入位置,limit 等于容量,下图表示写入了 4 个字节后的状态

              flip 动作发生后,position 切换为读取位置,limit 切换为读取限制

              读取 4 个字节后,状态

              clear 动作发生后,状态

              compact 方法,是把未读完的部分向前压缩,然后切换至写模式

              调试工具类
              public class ByteBufferUtil {    private static final char[] BYTE2CHAR = new char[256];    private static final char[] HEXDUMP_TABLE = new char[256 * 4];    private static final String[] HEXPADDING = new String[16];    private static final String[] HEXDUMP_ROWPREFIXES = new String[65536 >>> 4];    private static final String[] BYTE2HEX = new String[256];    private static final String[] BYTEPADDING = new String[16];    static {        final char[] DIGITS = "0123456789abcdef".toCharArray();        for (int i = 0; i > 4 & 0x0F];            HEXDUMP_TABLE[(i             int padding = HEXPADDING.length - i;            StringBuilder buf = new StringBuilder(padding * 3);            for (int j = 0; j 

上一篇:方舟单机怎么开服务器?

下一篇:服务器福袋怎么开?