BIO和NIO编程(待完善)

目录

IO模型

BIO

NIO

常见问题


IO模型

Java共支持3种网络编程IO模式:BIO,NIO,AIO

BIO

同步阻塞模型,一个客户端连接对应一个处理线程

代码示例:

Server端:

java 复制代码
public class BioServer {

    private static ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务器启动成功");
        while (true) {
            Socket socket = serverSocket.accept();
            System.out.println("客户端连接成功");
            executorService.execute(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                     BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {
                    String message;
                    while ((message = reader.readLine()) != null) {
                        System.out.println("收到消息: " + message);
                        writer.write("已收到消息: " + message);
                        writer.newLine();
                        writer.flush();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }
}

Client端:

java 复制代码
public class BioClient {

    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("localhost", 8888);
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
        String message;
        while ((message = consoleReader.readLine()) != null) {
            writer.write(message);
            writer.newLine();
            writer.flush();
            System.out.println("发送消息: " + message);
            System.out.println("收到回复: " + reader.readLine());
        }
        socket.close();
    }
}

执行结果:

存在问题:

  • IO操作是阻塞操作, 连接时读写会造成线程阻塞
  • 线程太多会造成CPU异常

应用场景:

BIO 方式适用连接数较小且固定的架构, 这种方式对服务器资源要求比较高, 但代码简单易理解。

NIO

同步非阻塞,服务器实现模式为一个线程可以处理多个请求(连接),客户端发送的连接请求都会注册到多路复用器selector上,多路复用器轮询到连接有IO请求就进行处理,JDK1.4开始引入。

应用场景:

NIO方式适用于连接数目多且连接比较短(轻操作) 的架构, 如聊天服务器, 弹幕系统, 服务器间通讯,编程比较复杂。

代码

java 复制代码
public class BioSelectorServer {

    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(9000));
        // 设置非阻塞
        serverSocket.configureBlocking(false);
        // 创建多路复用器
        Selector selector = Selector.open();
        // 注册serversocket到selector, 关注连接事件
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务启动成功");
        while (true) {
            // 阻塞等待需要处理的事件
            selector.select();
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                // 如果是连接事件  > 获取连接并且注册读事件
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = server.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    System.out.println("客户端连接成功");
                } else if (key.isReadable()) {
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(128);
                    int len = socketChannel.read(byteBuffer);
                    if (len > 0) {
                        System.out.println("接收到消息:" + new String(byteBuffer.array()));
                    } else {
                        System.out.println("客户端断开连接");
                        socketChannel.close();
                    }
                }
                // 从事件集合里删除本次处理的key,防止下次select重复处理
                iterator.remove();
            }
        }
    }
}

NIO的三大核心组件:

  1. channel 类似于流,每个 channel 对应一个 buffer缓冲区,buffer 底层就是个数组
  2. channel 会注册到 selector 上,由 selector 根据 channel 读写事件的发生将其交由某个空闲的线程处理
  3. NIO 的 Buffer 和 channel 都是既可以读也可以写

常见问题

为什么Netty使用NIO而不是AIO?

在Linux系统上,AIO的底层实现仍使用Epoll,没有很好实现AIO,因此在性能上没有明显的优势,而且被JDK封装了一层,不容易深度优化,Linux上AIO还不够成熟。Netty是异步非阻塞框架,Netty在NIO上做了很多异步的封装。

相关推荐
柳贯一(逆流河版)1 小时前
Spring 三级缓存:破解循环依赖的底层密码
java·spring·缓存·bean的循环依赖
该用户已不存在3 小时前
OpenJDK、Temurin、GraalVM...到底该装哪个?
java·后端
TT哇3 小时前
@[TOC](计算机是如何⼯作的) JavaEE==网站开发
java·redis·java-ee
Tina学编程3 小时前
48Days-Day19 | ISBN号,kotori和迷宫,矩阵最长递增路径
java·算法
青川入梦3 小时前
MyBatis极速通关上篇:Spring Boot环境搭建+用户管理实战
java·开发语言·mybatis
执子手 吹散苍茫茫烟波4 小时前
leetcode415. 字符串相加
java·leetcode·字符串
小韩博4 小时前
网络安全(Java语言)脚本 汇总(二)
java·安全·web安全
萤丰信息4 小时前
技术赋能安全:智慧工地构建城市建设新防线
java·大数据·开发语言·人工智能·智慧城市·智慧工地
带刺的坐椅4 小时前
Java MCP 的鉴权?好简单的啦
java·鉴权·mcp·solon-ai
Pocker_Spades_A4 小时前
飞算JavaAI家庭记账系统:从收支记录到财务分析的全流程管理方案
java·开发语言