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

相关推荐
wang_shu_mo_ran2 分钟前
MyBatis 从入门到进阶(一)
java·spring·mybatis
量化分析码农1 小时前
股票历史数据的复权参数对照:多级别返回的字段与数值差异
java·javascript·后端
猫猫不是喵喵.2 小时前
从0到1创建一个微服务项目
java·数据库·微服务·1024程序员节
瑞雪兆丰年兮2 小时前
JavaWeb-day13-SpringBootWeb事务管理&AOP
java·开发语言·springboot·javaweb·事务·web·aop
曲径海盗2 小时前
Try-Except怎么用,3个追问解答在自动化下的应用
java·jvm·oracle
真好啊又活了一天2 小时前
服务器和虚机配置IPV6
运维·服务器·github
Cosolar3 小时前
极简智库:快速搭建你的开源项目教程阅读平台,让 docs/ 目录被更多人看见
java·架构·github
墨痕诉清风3 小时前
SSRF漏洞实战记录+OSS桶命令执行+MCP漏洞
linux·服务器·数据库
nice_lcj5203 小时前
【从零理解 Spring AI · 16】Agent 与工作流:什么该写死,什么该让模型决定
java·人工智能·后端·spring ai·ai应用开发
布莱克6053 小时前
Swift 常量详解:从 let 到编译期优化
服务器·开发语言·ssh·swift·常量·let