NIO与BIO的区别

在以前搭建网络连接中,使用的BIO,在用户连接后专门创建一个线程和用户对接当用户没有使用时就会阻塞线程这也就是BIO为什么叫阻塞式通讯,而在今天高并发的情况下BIO会占用大量资源,阻塞线程会消耗系统资源形成一种浪费。所以NIO就是为了解决这个问题。

在传统的BIO模式中会使用线程来连接客户端,在一定程度上避免线程频繁的创建与销毁减少系统资源的使用,但是这仍然存在很大的问题。当用户离线时,线程不会直接注销,而是会阻塞或者空转,一直占用着线程资源,随着用户连接数越来越多所需要的线程资源就会越来越多降低整体新能,当有上万用户时所需要的资源就会十分夸张。但是NIO很好的避免了这个问题,下面来介绍NIO的组件。

NIO在Java中由三个组件构成分别为:缓存(ByteBuffer),管道(Channel)和选择器(Selector)。最为关键的选择器,选择器通过注册客户端发送过来的管道,之后直接进入休眠,等到有请求发送在开始读取连接管道中存在的数据处理好后再用管道原路返回。

接着是管道和缓存的使用,下面有一个服务端利用管道和缓存来实现NIO连接的例子:

复制代码
        int port=8080;
        ServerSocketChannel server=ServerSocketChannel.open();
        server.configureBlocking(false);
        server.bind(new InetSocketAddress(port));
        ByteBuffer buffer=ByteBuffer.allocate(1024);
        while (true) {
            Thread.sleep(1000);
            SocketChannel socketChannel = server.accept();
            if (socketChannel != null) {
                System.out.println("连接成功。。。");
                Thread.sleep(1000);
                int num=socketChannel.read(buffer);
                if(num>0) {
                    buffer.flip();
                    byte[] bytes=new byte[buffer.remaining()];
                    buffer.get(bytes);
                    System.out.println("client:"+new String(bytes));
                }
                buffer.clear();
                String msg = "连接成功。。。";
                buffer.put(msg.getBytes());
                buffer.flip();
                socketChannel.write(buffer);
                buffer.clear();
            }
        }

这里先创建一个端口用于接收在这个端口下创建的客户端,接着使用一个缓存空间接收管道中的数据,这里没有使用选择器而是采用轮询的方式效率会不如选择器。

客户端则需要创建管道和缓存空间来将需要的数据传给服务器或从服务器那里读取数据,实现如下:

复制代码
        String ip="127.0.0.1";
        int port=8080;
        SocketChannel channel=SocketChannel.open();
        channel.configureBlocking(false);//禁止阻塞
        channel.connect(new InetSocketAddress(ip,port));
        ByteBuffer buffer=ByteBuffer.allocate(1024);

        while (!channel.finishConnect()){
            System.out.println("客户端正在连接服务器。。。");
        }
        Scanner scanner=new Scanner(System.in);
        String message=scanner.nextLine();
        buffer.put(message.getBytes());
        buffer.flip();//切换为读模式
        Thread.sleep(100);
        channel.write(buffer);
        buffer.clear();

        int readNum=channel.read(buffer);
        if(readNum>0){//只有大于0才读到数据,-1时断开连接
            buffer.flip();
            byte[] bytes=new byte[buffer.remaining()];
            buffer.get(bytes);//将读到的数据存入自定义数组中
            String msg=new String(bytes);
            System.out.println("client:"+msg);
        }

这里需要用while循环来连接至客户端防止一次没连接上,利用缓存将字符串转为字节流,再将字节流输入管道中,服务器通过轮询来获取到数据并利用管道返回结果。

相关推荐
吳所畏惧1 小时前
宝塔面板Redis密码修改指南:SSH命令修改 vs 面板UI界面修改,哪个更靠谱?
运维·服务器·数据库·redis·缓存·ssh
DFT计算杂谈1 小时前
无 Root 权限在 Tesla K80 零门槛部署 DeepSeek 大模型
linux·服务器·网络·数据库·机器学习
维天说2 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json
Zhang~Ling2 小时前
从 fopen 到 struct file:从零开始拆解 Linux 文件 I/O
linux·运维·服务器
爱写代码的阿森2 小时前
鸿蒙三方库 | harmony-utils之PreferencesUtil首选项数据监听详解
服务器·华为·harmonyos·鸿蒙·huawei
爱写代码的森2 小时前
蒙三方库 | harmony-utils之FileUtil文件重命名与属性查询详解
linux·运维·服务器·华为·harmonyos·鸿蒙·huawei
Zane19943 小时前
并发 vs 并行:别再傻傻分不清了,一文讲透 Java 并发编程的第一课
java·后端
噢,我明白了3 小时前
java中Excel的导入和导出(EasyExcel)
java·开发语言·excel
吠品3 小时前
Zabbix Web界面误报Server未运行的排查与解决
java·服务器·数据库
啊湘4 小时前
天气查询API接口 按月Token鉴权 实时天气 物联网可用 文档齐全
java·后端·struts