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

相关推荐
小羊没烦恼!3 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里3 天前
java中的继承和多态的区别
java
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕3 天前
JSONObject与JSONArray封装数据格式区别
java·json
虎头金猫3 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖3 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时3 天前
01-06-A-JVM排查实战详解
java·jvm
vipxieliang3 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
ba_pi3 天前
mysql 查询所有表名并授权
java