分布式学习笔记(六)——BIO、NIO与AIO

BIO、NIO与AIO的区别

BIO

BIO (Blocking I/O),即同步阻塞I/O。数据的读取写入必须阻塞在一个线程内等待其完成。在JDK1.4之前的IO操作都是BIO。

NIO

NIO (New I/O),也可以认为是(Non-Blocking I/O),同步非阻塞I/O,DK1.4引入的新API,它支持面向缓c存的,基于通道的I/O操作方法,提供了 Channel , Selector,Buffer等抽象。

AIO

AIO (Asynchronous I/O) - 异步IO,AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会阻塞在,当后台处理完成,操作系统会通知相应的线程进行后续的操作。

NIO与BIO的区别

1、BIO面向流,而NIO面向的是缓冲。BIO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。NIO将数据读取到一个它稍后处理的缓冲区。
2、BIO的I/O操作是阻塞的,而NIO的I/O操作是非阻塞的。BIO在执行read/write方法时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。而NIO在执行read/write方法时,线程不阻塞,有数据就去读或者写。无需等待。
3、NIO的选择器允许一个单独的线程来监视多个通道,而BIO通常是一个线程对应一个tcp连接
4、NIO在读取数据时,因为不知道数据有没有读完,所以在处理时会复杂一点,而BIO因为线程阻塞直到读完,所以处理起来会简单一点。所以对大量连接,但是每个连接传输的数据很小的情况使用NIO会比较好,而对于连接少,但是数据传输量大的情况使用BIO会比较好。

NIO简介

Java NIO 由三个核心部分组成:Channel(通道)、Buffer(缓冲区)、Selector(选择器)。

Channel和Buffer

基本上,所有的 IO 在NIO 中都从一个Channel 开始。Channel 有点象流。 数据可以从Channel读到Buffer中,也可以从Buffer 写到Channel中。
在这里插入图片描述
Channel的种类有:FileChannel(文件)、DatagramChannel(UDP)、SocketChannel(tcp)、ServerSocketChanne(可以监听新进来的TCP连接)。
Buffer的类型有:ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer。

Selector

Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。
在这里插入图片描述
使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等。

NIO代码示例

server:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioServer {

    private int port;
    private Selector selector;
    private ByteBuffer buffer = ByteBuffer.allocate(1024);


    public NioServer(int port){
        try {
            this.port = port;
            //打开一个ServerSocket通道,相当于ServerSocket
            ServerSocketChannel channel = ServerSocketChannel.open();
            //设置地址和端口
            channel.bind(new InetSocketAddress(port));
            //设置为非阻塞模式,使用selector,channel必须是非阻塞的
            channel.configureBlocking(false);
            //打开选择器
            selector = Selector.open();
			//将ServerSocket通道注册到这个Selector上
			//ServerSocketChannel只能用OP_ACCEPT状态,
            channel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void listen(){

        try {
            while (true){
            	//这里会阻塞,等待连接
            	//NIO是I/O操作不会阻塞,如read和Write操作。
                selector.select();
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> iter = keys.iterator();

                while (iter.hasNext()){
                    SelectionKey key = iter.next();
                    iter.remove();
                    process(key);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void process(SelectionKey key) throws IOException {
        if(key.isAcceptable()){
            ServerSocketChannel serverChannel = (ServerSocketChannel)key.channel();
            SocketChannel channel =  serverChannel.accept();
            channel.configureBlocking(false);
            //连接成功,注册到selector上,设置为读监听
            key = channel.register(selector,SelectionKey.OP_READ);

        }else if(key.isReadable()){
        	//通道读已就绪
            SocketChannel channel = (SocketChannel)key.channel();
            //将读取到的数据放到buffe中
            int len = channel.read(buffer);
            if(len>0){
            	//将buffer从写模式切换到读模式
                buffer.flip();
                String content = new String(buffer.array(),0,len);
                //将通道注册到selector,设置为写监听
                key = channel.register(selector,SelectionKey.OP_WRITE);
                //在key上携带一个附件,一会再写出去
                key.attach(content);
                System.out.println("读取内容:" + content);

            }

        }else if(key.isWritable()){
            SocketChannel channel = (SocketChannel)key.channel();

            String content = (String)key.attachment();
            //将buffer中的数据读到通道中
            channel.write(ByteBuffer.wrap(("输出:" + content).getBytes()));

            channel.close();
        }

    }
    public static void main(String[] args) {
        new NioServer(8080).listen();
    }

}

client:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

public class Nioclient {



    public static void main(String[] args) throws IOException, InterruptedException {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.connect(new InetSocketAddress("localhost", 8080));
        socketChannel.configureBlocking(false);

        String info = "hello server!";
        buffer.put(info.getBytes());
        buffer.flip();

        while (buffer.hasRemaining()){
            socketChannel.write(buffer);
        }

        buffer.clear();
        Thread.currentThread().sleep(3000);
        int len = socketChannel.read(buffer);
        String msg = new String(buffer.array(),0,len);
        System.out.println(msg);
        socketChannel.close();

    }
}

参考文章:https://www.cnblogs.com/diegodu/p/6823855.html
参考文章:https://www.cnblogs.com/duanxz/p/6759689.html
参考文章:https://ifeve.com/java-nio-all/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值