栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

NIO有关知识点(一)

NIO有关知识点(一)

目录

BIO、NIO区别

概念上

具体体现

BIO

NIO


BIO、NIO区别

概念上

BIO:阻塞IO。

NIO:非阻塞IO。

具体体现

BIO

BIO服务端代码。具体阻塞地方写在了代码注释里。

    public static void main(String[] args) {
        try {
            ServerSocket socket = new ServerSocket(9000);
            while (true){
                System.out.println("等待连接");
                Socket accept = socket.accept();//未获取连接则阻塞
                System.out.println("有客户端连接");
                handler(accept);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void handler(Socket accept) throws IOException {
        byte[] bytes = new byte[1024];
        System.out.println("准备读取");
        int read = accept.getInputStream().read(bytes); //未读到数据则阻塞
        System.out.println("读取完毕");
        if (read!=-1){
            System.out.println("数据为:"+new String(bytes,0,read));
        }
        //数据未处理完,则阻塞下一条数据
    }

BIO局限性太大,以上代码一次只允许处理一个连接。我们稍加改造,即使我们把handler方法放在多线程里,可以处理多个消息。但是仍存在很大的问题:如请求过多造成内存溢出,或是有多个连接但是是空连接一直不发送信息(造成资源浪费)。

BIO早已不能满足日益增长的用户量。如果你并发量很小,还是可以用BIO的。

NIO

NIO服务端代码。精华写在了注释里。

    static List list = new ArrayList();
    public static void main(String[] args) throws IOException {
        //设置端口
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(9000));
        //设置连接为非阻塞
        serverSocket.configureBlocking(false);
        System.out.println("服务启动成功");
        //非阻塞的一直循环
        while (true){
            SocketChannel accept = serverSocket.accept();
            //如果有连接
            if(accept!=null){
                System.out.println("有客户端连接");
                //设置管道为非阻塞
                accept.configureBlocking(false);
                list.add(accept);
            }
            Iterator iterator = list.iterator();
            //遍历管道去拿数据,read是不阻塞的。
            while (iterator.hasNext()){
                SocketChannel sc = iterator.next();
                ByteBuffer buffer = ByteBuffer.allocate(128);
                int read = sc.read(buffer);
                if(read>0){
                    System.out.println("收到消息:"+new String(buffer.array()));
                }else if(read==-1){
                    iterator.remove();
                    System.out.println("客户端断开");
                }
            }
        }

    }

天生可以支持多个连接,可以设置连接和read为非阻塞。一个线程处理多个客户端。后边使用遍历连接去接受数据。

以上NIO程序存在的问题:while(iterator.hasNext())遍历效率低。

为了解决这个问题,引入了selector多路复用器。把连接事件和读写事件分开,如果有写入事件,只需要遍历写入的socket。代码如下,解释在注释。

    public static void main(String[] args) throws IOException {
        //开放端口
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(9000));
        serverSocket.configureBlocking(false);
        //打开selector处理channel。linux帮我们创建了一个epoll实例(epoll_create)
        Selector selector = Selector.open();
        //把serverSocket注册到selector,并指定监听连接
        SelectionKey selectionKey = serverSocket.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务启动成功");
        while (true){
            //阻塞等待需要处理的事件发生
            selector.select(); //底层调用epoll_ctl函数,启用监听。调用epoll_wait去看另一个                                                
                               // 集合是否有活动事件,没有则阻塞。
            //获取在selector里边的全部事件
            Set selectionKeys = selector.selectedKeys();
            Iterator 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 if(len==-1){
                        System.out.println("断开连接");
                        socketChannel.close();
                    }
                }
                iterator.remove();
            }
        }
    }

这样就解决了无效遍历的问题。想要更了解epoll,可以读这个文章

Java中套接字(socket)以及有关概念入门_运气不好努力来凑-CSDN博客套接字入门理解,还不懂的可以入门学习https://blog.csdn.net/wai_58934/article/details/122848372?spm=1001.2014.3001.5501今天先到这里,白嫖直播公开课去,明天继续

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/734112.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号