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

相关推荐
Dola_Pan2 小时前
Linux文件IO(二)-文件操作使用详解
java·linux·服务器
wang_book3 小时前
Gitlab学习(007 gitlab项目操作)
java·运维·git·学习·spring·gitlab
蜗牛^^O^3 小时前
Docker和K8S
java·docker·kubernetes
从心归零4 小时前
sshj使用代理连接服务器
java·服务器·sshj
IT毕设梦工厂5 小时前
计算机毕业设计选题推荐-在线拍卖系统-Java/Python项目实战
java·spring boot·python·django·毕业设计·源码·课程设计
Ylucius6 小时前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
七夜zippoe6 小时前
分布式系统实战经验
java·分布式
是梦终空6 小时前
JAVA毕业设计176—基于Java+Springboot+vue3的交通旅游订票管理系统(源代码+数据库)
java·spring boot·vue·毕业设计·课程设计·源代码·交通订票
落落落sss6 小时前
sharding-jdbc分库分表
android·java·开发语言·数据库·servlet·oracle
码爸6 小时前
flink doris批量sink
java·前端·flink