栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

BIO和NIO

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

BIO和NIO

BIO和NIO

Java 中的 BIO、NIO和 AIO 理解为是 Java 语言对操作系统的各种 IO 模型的封装。程序员在使用这些 API 的时候,不需要关心操作系统层面的知识,也不需要根据不同操作系统编写不同的代码。只需要使用Java的API就可以了。

BIO

同步阻塞I/O模式:因为socket.accept()、 socket.read()、 socket.write() 是同步阻塞的。举例:当服务器用read去客户端的的数据时,是无法预知对方是否已经发送数据的。因此在收到数据之前,当前线程会被挂起。无法做其他的工作。直到客户端把数据发过来。此时如果有另一个客户端要请求连接服务器,服务器必须开启另一个线程来处理客户端请求。每有一个客户端,服务器就要开启一个线程来处理。处理完成之后,线程才销毁。如果有大量的客户端连接请求,就要创建大量的线程,而线程的创建和销毁成本很高。并且可能会导致线程堆栈溢出、创建新线程失败等问题。不过可以通过线程池来优化,线程使用完后,不再是销毁而是放回线程池,供下一个请求使用。减少了线程的创建和销毁成本。线程池可以设置最大线程数量,因此它占用的资源是可控的。但也带来了一个问题,它的并发量有限,最大并发量为线程池的最大线程数量。

NIO

同步非阻塞的I/O模型:当服务器用read去客户端的的数据时,如果客户端没有发送数据,直接返回0,不会阻塞线程。因此在收到数据之前,该线程可以继续做其他的事情。 这段时间通常被用于执行其它通道上的IO操作,实现一个线程管理多个通道。

NIO有三大组件:Buffer(缓冲区),Channel(通道),Selector(选择器)

Buffer(缓冲区):NIO是面向缓冲区的。NIO中数据的读和写都必须经过Buffer。 Buffer可读可写,使用flip()方法切换读,使用clear()方法切换到写。若Buffer中有未读且后续还需要的数据,使用compact()方法切换到写(在未读的数据后继续写)。

Channel(通道):Channel和流非常相似,区别是:通道是双向的(可读可写),流是单向的(只能读或写)。NIO通道本身不存储数据,只是打开与IO设备之间的连接,所以通道必须要和缓冲区配合使用。NIO的强大功能部分来自于Channel的非阻塞特性,可以手动设置为非阻塞(注意:文件通道总是阻塞式的,因此不能设置为非阻塞)。

Selector(选择器)
Selector能够轮询检测多个注册的通道上是否有事件发生(事件:读就绪/写就绪/有新连接到来)。如果有事件发生,会通知Selector,然后针对每个事件进行相应的处理。实现一个线程管理多个通道。

客户端代码

 public static void client(){
        //设置缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        SocketChannel socketChannel = null;
        try
        {
            // 获取客户端的通道
            socketChannel = SocketChannel.open();
             // 手动设置为非阻塞
            socketChannel.configureBlocking(false);
            // 发起连接
            socketChannel.connect(new InetSocketAddress("10.10.195.115",8080));
            // 需要判断是否连接连接完成
            if(socketChannel.finishConnect())
            {
                int i=0;
                while(true)
                {
                    TimeUnit.SECONDS.sleep(1);
                    String info = "I'm "+i+++"-th information from client";             
                    //切换到写模式
                    buffer.clear();
                    //将数据写入缓冲区
                    buffer.put(info.getBytes());
                    //切换到读模式
                    buffer.flip();
                    //将缓冲区的数据写入通道。
                    while(buffer.hasRemaining()){
                        System.out.println(buffer);
                        socketChannel.write(buffer);
                    }
                }
            }
        }
        catch (IOException | InterruptedException e)
        {
            e.printStackTrace();
        }
        finally{
        //关闭资源
            try{
                if(socketChannel!=null){
                    socketChannel.close();
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }

服务端代码

public class ServerConnect
{
    private static final int BUF_SIZE=1024;
    private static final int PORT = 8080;
    private static final int TIMEOUT = 3000;
    public static void main(String[] args)
    {
        selector();
    }
    public static void handleAccept(SelectionKey key) throws IOException{
    //先从事件身上获取到通道
        ServerSocketChannel ssChannel = (ServerSocketChannel)key.channel();
        //建立连接
        SocketChannel sc = ssChannel.accept();
        // 手动设置为非阻塞
        sc.configureBlocking(false);
       // 注册一个read事件
        sc.register(key.selector(), SelectionKey.OP_READ,ByteBuffer.allocateDirect(BUF_SIZE));
    }
    public static void handleRead(SelectionKey key) throws IOException{
        SocketChannel sc = (SocketChannel)key.channel();
        ByteBuffer buf = (ByteBuffer)key.attachment();
        long bytesRead = sc.read(buf);
        while(bytesRead>0){
            buf.flip();
            while(buf.hasRemaining()){
                System.out.print((char)buf.get());
            }
            System.out.println();
            buf.clear();
            bytesRead = sc.read(buf);
        }
        if(bytesRead == -1){
            sc.close();
        }
    }
    public static void handleWrite(SelectionKey key) throws IOException{
        ByteBuffer buf = (ByteBuffer)key.attachment();
        buf.flip();
        SocketChannel sc = (SocketChannel) key.channel();
        while(buf.hasRemaining()){
            sc.write(buf);
        }
        buf.compact();
    }
    public static void selector() {
        Selector selector = null;
        ServerSocketChannel ssc = null;
        try{
            // 开启选择器
            selector = Selector.open();
            // 开启服务器端的通道
            ssc= ServerSocketChannel.open();
            // 绑定端口
            ssc.socket().bind(new InetSocketAddress(PORT));
            // 设置为非阻塞
            ssc.configureBlocking(false);
            // 将通道注册到选择器上
            ssc.register(selector, SelectionKey.OP_ACCEPT);
            //死循环
            while(true){
               //轮询获取选择器上已经“准备就绪”的事件。阻塞TIMEOUT时间,退出本次循环。
                if(selector.select(TIMEOUT) == 0){
                    System.out.println("==");
                    continue;
                }
                //获取选择器中所有注册的“选择键(已就绪的监听事件)”
                Iterator iter = selector.selectedKeys().iterator();
                while(iter.hasNext()){
                     // 获取单个事件
                    SelectionKey key = iter.next();
                    //可能是accept
                    if(key.isAcceptable()){
                     //处理事件
                        handleAccept(key);
                    }
                    // 可能是read
                    if(key.isReadable()){
                        handleRead(key);
                    }
                    // 可能是write
                    if(key.isWritable() && key.isValid()){
                        handleWrite(key);
                    }
                    //判断是否连接,没有移除事件。
                    if(key.isConnectable()){
                        System.out.println("isConnectable = true");
                    }
                    iter.remove();
                }
            }
        }catch(IOException e){
            e.printStackTrace();
        }finally{
            try{
                if(selector!=null){
                    selector.close();
                }
                if(ssc!=null){
                    ssc.close();
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/346095.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

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

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