NIO编程介绍

x33g5p2x  于2022-02-14 转载在 其他  
字(3.7k)|赞(0)|评价(0)|浏览(156)

I/O模型

java支持3种网络编程模型I/O模式:BIO(同步并阻塞)、NIO(同步非阻塞)、AIO(异步非阻塞)

阻塞指的是访问IO的线程是否会阻塞(或等待)。线程访问资源,该资源是否准备就绪的一种处理方式。

阻塞与非阻塞:

同步与异步:

1.1 BIO

BIO:同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池机制改善。

代码示例:

public class ServerDemo {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket=new ServerSocket(9999);
        ExecutorService executorService = Executors.newCachedThreadPool();
        while (true){
            Socket socket=serverSocket.accept();
            System.out.println("有客户端连接");
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    InputStream inputStream = null;
                    try {
                        inputStream = socket.getInputStream();
                        byte[] b=new byte[1024];
                        int read = inputStream.read(b);
                        System.out.println("收到客户端信息:"+new String(b,0,read));
                        OutputStream outputStream = socket.getOutputStream();
                        outputStream.write("你好客户端".getBytes(Charset.defaultCharset()));
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}
public class ClientDemo {

    public static void main(String[] args) throws IOException {
        Socket socket=new Socket("127.0.0.1",9999);
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("你好服务端".getBytes(Charset.defaultCharset()));
        InputStream inputStream = socket.getInputStream();
        byte[] bytes=new byte[1024];
        inputStream.read(bytes);
        System.out.println("收到服务端消息:"+new String(bytes));
        socket.close();

    }
}

BIO问题分析:

  1. 每个请求都需要创建独立的线程,与对应的客户端进行数据Read、业务处理、数据Write
  2. 并发数较大时,需要创建大量线程来处理连接,系统资源占用较大
  3. 连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在Read操作上,造成资源阻塞。

1.2 NIO

NIO:同步非阻塞,服务器实现模式为一个线程处理多个请求(连接),即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求就进行处理。

代码示例:

public class NioSelectorServer {

    public static void main(String[] args) throws IOException, InterruptedException {
        //1.打开服务器通道
        ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
        //2.绑定端口号
        serverSocketChannel.bind(new InetSocketAddress(9999));
        //3.设置通道为非阻塞
        serverSocketChannel.configureBlocking(false);
        //4.创建选择器
        Selector selector = Selector.open();
        //5.将服务端通道注册到选择器上,并指定注册监听事件为OP_ACCEPT
        serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
        while (true){
            //6.检查选择器释放有事件
//            int select = selector.select(2000);
            int select = selector.select();
            if(select==0){
                System.out.println("无连接");
                continue;
            }
            //7.获取事件集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()){
                SelectionKey selectionKey = iterator.next();
                //8.判断事件是否是连接事件
                if(selectionKey.isAcceptable()){
                    //9.得到客户端通道,并将通道注册到选择器上
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    System.out.println("有客户端连接");
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector,SelectionKey.OP_READ);
                }
                //10.判断是否是读就绪事件
                else if(selectionKey.isReadable()){
                    SocketChannel channel = (SocketChannel)selectionKey.channel();
                    ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
                    //11.得到客户端通道,读取数据到缓冲区
                    int read = 0;
                    read = channel.read(byteBuffer);
                    System.out.println("客户端消息:"+new String(byteBuffer.array()));
                    System.out.println("模拟业务处理中。。。");
                    Thread.sleep(5000);
                    if(read>0){
                        //12.回写数据给客户端
                        channel.write(ByteBuffer.wrap("你好客户端".getBytes(StandardCharsets.UTF_8)));
                        channel.close();
                    }
                }
                //13.从集合删除对应事件,防止二次处理
                iterator.remove();
            }
        }
    }
}

1.3 AIO

AIO引入了异步通道的概念,采用了Proactor模式,简化了程序编写。它的特点是先由操作系统完成后才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间比较长的应用。
Proactor模式是一个消息异步通知的设计模式,Proactor通知的部署就绪事件,而是操作完成事件。

适用场景:

  1. BIO适用于连接数比较小且固定的架构,这种方式对服务器资源要求比较高
  2. NIO适用于连接数目多且比较短的架构,比如聊天服务器,弹幕系统,服务期间通讯等
  3. AIO适用于连接数多且连接比较长的架构,比如相册服务器。

NIO编程

2.1 NIO介绍

Java NIO是JDK提供的新API。NIO有三个核心部分:Channel,Buffer,Selector。NIO是面向缓冲区编程的。JAVA NIO的非阻塞模式,是一个线程从某个通道发送或读取数据,仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是阻塞线程。

通俗理解:NIO是可以做到用一个线程来处理多个操作的。假设有1000个请求过来,根据实际情况,可以分配50或100个线程来处理。不像BIO那样,非得分配1000个线程。

NIO和BIO比较

  1. BIO是以流的方式处理数据,而NIO是以缓冲区的方式处理数据
  2. BIO是阻塞的,NIO是非阻塞的
  3. BIO基于字节流和字符流操作,而NIO是基于Channel和Buffer进行操作。NIO基于Selector监听多个通道的事件。

书山有路勤为径,学海无涯苦作舟

相关文章

微信公众号

最新文章

更多