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上做了很多异步的封装。

相关推荐
float_六七2 小时前
IntelliJ IDEA双击Ctrl的妙用
java·ide·intellij-idea
能摆一天是一天3 小时前
JAVA stream().flatMap()
java·windows
颜如玉4 小时前
🤲🏻🤲🏻🤲🏻临时重定向一定要能重定向🤲🏻🤲🏻🤲🏻
java·http·源码
程序员的世界你不懂5 小时前
【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇
java·前端·数据库
星空寻流年5 小时前
设计模式第一章(建造者模式)
java·设计模式·建造者模式
gb42152876 小时前
java中将租户ID包装为JSQLParser的StringValue表达式对象,JSQLParser指的是?
java·开发语言·python
曾经的三心草6 小时前
Python2-工具安装使用-anaconda-jupyter-PyCharm-Matplotlib
android·java·服务器
Metaphor6926 小时前
Java 高效处理 Word 文档:查找并替换文本的全面指南
java·经验分享·word
ChinaRainbowSea6 小时前
7. LangChain4j + 记忆缓存详细说明
java·数据库·redis·后端·缓存·langchain·ai编程
stormsha6 小时前
飞算JavaAI炫技赛电商系统商品管理模块的架构设计与实现
java·架构·鸿蒙系统