非阻塞式 I/O 模型的工作原理【NIO】-2

优化上一篇文上的代码。

复制代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class NonBlockingServer {
    public static void main(String[] args) throws IOException {
        // 创建 Selector
        Selector selector = Selector.open();

        // 创建 ServerSocketChannel 并绑定端口
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(8080));
        serverSocketChannel.configureBlocking(false);

        // 将 ServerSocketChannel 注册到 Selector 上,并指定监听事件为接受连接事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        System.out.println("Server started, listening on port 8080...");

        while (true) {
            // 阻塞等待事件发生
            selector.select();

            // 获取发生事件的 SelectionKey 集合
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectedKeys.iterator();

            // 遍历处理事件
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();

                // 创建新线程处理事件
                new Thread(new EventHandler(key)).start();
            }
        }
    }

    // 处理事件的线程类
    static class EventHandler implements Runnable {
        private SelectionKey key;

        public EventHandler(SelectionKey key) {
            this.key = key;
        }

        @Override
        public void run() {
            try {
                // 处理接受连接事件
                if (key.isAcceptable()) {
                    ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                    SocketChannel clientChannel = serverChannel.accept();
                    clientChannel.configureBlocking(false);
                    clientChannel.register(key.selector(), SelectionKey.OP_READ);
                    System.out.println("Client connected: " + clientChannel.getRemoteAddress());
                }

                // 处理读事件
                if (key.isReadable()) {
                    SocketChannel clientChannel = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int bytesRead = clientChannel.read(buffer);
                    if (bytesRead != -1) {
                        buffer.flip();
                        byte[] bytes = new byte[buffer.remaining()];
                        buffer.get(bytes);
                        String message = new String(bytes);
                        System.out.println("Received message from client: " + message);

                        // 原样返回给客户端
                        clientChannel.write(ByteBuffer.wrap(bytes));
                    } else {
                        // 客户端关闭连接
                        key.cancel();
                        clientChannel.close();
                        System.out.println("Client disconnected: " + clientChannel.getRemoteAddress());
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

在这个优化后的代码中,我们将处理事件的逻辑封装在 EventHandler 类中,并在遍历处理事件时创建新的线程来处理每个事件。这样可以实现并发处理不同连接的读写事件,提高系统的并发处理能力。

相关推荐
泡泡鱼(敲代码中)7 分钟前
Python语法技术学习笔记
开发语言·笔记·python·学习·pycharm
hqyjzsb32 分钟前
Python 技术人转型 AI:CAIE Level I、Level II 对比怎么选
开发语言·人工智能·python·金融·数据挖掘·数据分析·aigc
承渊政道1 小时前
【Python编程—从入门到实践】(Python字典:从基础语义到现代工程实践)
开发语言·python·pycharm·字典·嵌套
luj_17682 小时前
一线一区一变破解人盯人防守密码
开发语言·网络·c++·经验分享·算法
名字还没想好☜2 小时前
Python 字符编码实战:encode/decode、UnicodeDecodeError 与 open 的 encoding 坑
开发语言·后端·python·编程语言
萧瑟余晖2 小时前
持久层选型与框架对比详解
开发语言·架构
CodeStats2 小时前
【Java 类加载器】Java 类加载器完整体系深度拆解(上):从 JVM 启动到双亲委派模型
java·开发语言·jvm·classloader·双亲委派
软件黑马王子2 小时前
24.Editor 资源加载:主要作用和基本原理
开发语言·前端框架·c#
luj_17682 小时前
中锋卡位与开放线博弈
c语言·开发语言·网络·经验分享·算法
未来之窗软件服务2 小时前
计算机二级[英文]-C 逻辑运算和fopen—东方仙盟
c语言·开发语言·仙盟创梦ide·东方仙盟