NIO编程介绍

博客 动态
0 226
优雅殿下
优雅殿下 2022-02-13 19:55:17
悬赏:0 积分 收藏

NIO编程介绍

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监听多个通道的事件。
书山有路勤为径,学海无涯苦作舟
posted @ 2022-02-13 19:30 女友在高考 阅读(6) 评论(0) 编辑 收藏 举报
回帖
    优雅殿下

    优雅殿下 (王者 段位)

    2018 积分 (2)粉丝 (47)源码

    小小码农,大大世界

     

    温馨提示

    亦奇源码

    最新会员