NIO, AIO, BIO is a what?

I. Introduction

NIO

A synchronous non-blocking I / O.

AIO

Non-blocking asynchronous I / O.

BIO

Synchronous blocking IO operation.

Second, the Glossary

Blocking and non-blocking

When a thread executes a blocking operation, we can only wait, but can not perform other things.
Non-blocking game is no need to wait, direct return, continue with the next operation.

Synchronous and asynchronous

Synchronous asynchronous operation mechanism is that when we synchronize, follow-up task is waiting for the current calls to return, will be the next step.
Asynchronous contrast, other tasks without waiting for the current calls to return, often rely on the event, such as a callback mechanism to implement the order of the relationship between tasks.

IO classification

Press operation data are divided into: byte stream (Reader, Writer) and character stream (InputStream, OutputStream)
by flow point: input stream (Reader, InputStream) and output streams (Writer, OutputStream)

Third, actual demo

BIO

Server code:

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * @ProjectName: onereader
 * @Package: com.onereader.webblog.common.bio
 * @ClassName: BIOServer
 * @Author: onereader
 * @Description: ${description}
 * @Date: 2019/9/1 14:30
 * @Version: 1.0
 */
public class BIOServer {

    ServerSocket server;
    //服务器
    public BIOServer(int port){
        try {
            //把Socket服务端启动
            server = new ServerSocket(port);
            System.out.println("BIO服务已启动,监听端口是:" + port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 开始监听,并处理逻辑
     * @throws IOException
     */
    public void listener() throws IOException{
        //死循环监听
        while(true){
            //等待客户端连接,阻塞方法
            Socket client = server.accept();
            //获取输入流
            InputStream is = client.getInputStream();
            //定义数组,接收字节流
            byte [] buff = new byte[1024];
            int len = is.read(buff);
            //只要一直有数据写入,len就会一直大于0
            if(len > 0){
                String msg = new String(buff,0,len);
                System.out.println("收到" + msg);
            }
        }
    }

    public static void main(String[] args) throws IOException {
        new BIOServer(9999).listener();
    }
}

Client code:

import java.io.OutputStream;
import java.net.Socket;
import java.util.concurrent.CountDownLatch;
/**
 * @ProjectName: onereader
 * @Package: com.onereader.webblog.common.bio
 * @ClassName: BIOClient
 * @Author: onereader
 * @Description: ${description}
 * @Date: 2019/9/1 14:31
 * @Version: 1.0
 */
public class BIOClient {

    public static void main(String[] args){
        int count = 10;
        //计数器,模拟10个线程
        final CountDownLatch latch = new CountDownLatch(count);
        for(int i = 0 ; i < count; i ++){
            new Thread(){
                @Override
                public void run() {
                    try{
                        //等待,保证线程一个一个创建连接
                        latch.await();
                        //创建socket,连接服务端
                        Socket client = new Socket("localhost", 9999);
                        //获取输出流
                        OutputStream os = client.getOutputStream();
                        //获取当前线程名
                        String name = "客户端线程:"+Thread.currentThread().getName();
                        //发送到服务端
                        os.write(name.getBytes());
                        //关闭输入流
                        os.close();
                        //关闭socket连接
                        client.close();

                    }catch(Exception e){

                    }
                }

            }.start();
            //计数器减1
            latch.countDown();
        }
    }
}

result:

收到客户端线程:Thread-1
收到客户端线程:Thread-4
收到客户端线程:Thread-0
收到客户端线程:Thread-3
收到客户端线程:Thread-2
收到客户端线程:Thread-6
收到客户端线程:Thread-8
收到客户端线程:Thread-7
收到客户端线程:Thread-5
收到客户端线程:Thread-9

The following simple to explain, after starting the server, the server would have been blocked in a wait state, waiting for the client to connect, before proceeding to read the information sent by the client, and then enters a loop obstruction, waiting for a new connection to handle the new information data. Above, we create a 10 threads simulate a client connects the server to send information, the server in cycle blocking the way, receiving a pass over client information.

NIO

NIO three main components:

Channel (channel), Buffer (buffer), Selector (selector)

NIO execution process:

When a client using NIO connection to the server, the first will open Channel (channel), then the data is written to Buffer (buffer), and the Buffer data sent through the channel, the last event to register a selector.
The server will first open the Channel (channel), then listens for the selector in the event, after the event if there is found to obtain Buffer from the channel, and then read the data from the Buffer. If not, the cycle has been listening to it.

Channel (Channel)

Channel is an object, which can read and write data.
Channel in both directions, both read and can write.
Channel can be read asynchronously.
Channel must pass the reading and writing buffer object.

Channel Java NIO mainly in the following types:
FileChannel: reading data from a file
DatagramChannel: UDP network protocol to read and write data
SocketChannel: read the TCP network protocol data
ServerSocketChannel: TCP connection can monitor

Buffer (buffer)

Buffer is an object that contains a number to be written to or read Stream object. Channel application can not directly read and write operations, must be carried out by Buffer, i.e. Channel is to read and write data through Buffer.

In NIO, all data are treated with Buffer, which is read and write data transfer NIO pool. Buffer is essentially an array, usually a byte of data, but may also be other types of arrays. However, a buffer is not just an array importantly, it provides a structured access to data, but also can read and write process tracking system.

Buffer property description:

The maximum number of data elements can be accommodated in the buffer: capacity (Capacity). This capacity is set in a buffer zone creation, and can never be changed.
Upper bound (Limit): The first can not be read or written element buffer. Or, the existing count in the buffer element.
The next index is to be read or written element: location (Position). Location is updated automatically by a respective get () and put () function.
The next index is to be read or written elements: Mark (Mark). Location is updated automatically by a respective get () and put () function.

Reading and writing data steps:

1. Write data to Buffer;
2. Flip call () method;
3. The data from the Buffer;
4. Invoke clear () method or a compact () method.

When data is written to Buffer, Buffer will record the number of write data. Once the data to be read is required () method Buffer switching from write mode to read mode flip. In the read mode, all data written to Buffer previously read.

Once you have read all the data, we need to empty the buffer, it can be written again. There are two ways to be able to empty the buffer: call clear () or compact () method. clear () method clears the entire buffer. compact () method will only read data has been cleared. Any unread data is moved to the beginning of the buffer, the new data will be written back into the data buffer unread.

There are several major Buffer:
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer

Selector (selector)

Whether the client or the server can be registered with the Selector in the event, and then listen for events, and finally processed differently depending on the event.

The following look at the code
client:

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.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
/**
 * @ProjectName: onereader
 * @Package: com.onereader.webblog.common.nio
 * @ClassName: NIOClient
 * @Author: onereader
 * @Description: ${description}
 * @Date: 2019/9/1 13:41
 * @Version: 1.0
 */
public class NIOClient {
    private final InetSocketAddress serverAdrress = new InetSocketAddress("localhost", 9999);
    private Selector selector = null;
    private SocketChannel client = null;
    private Charset charset = Charset.forName("UTF-8");

    public NIOClient() throws IOException{
        //1.连接远程主机的IP和端口
        client = SocketChannel.open(serverAdrress);
        client.configureBlocking(false);

        //打开选择器,注册读事件
        selector = Selector.open();
        client.register(selector, SelectionKey.OP_READ);
    }

    public void session(){
        //开辟一个新线程从服务器端读数据
        new Reader().start();
        //开辟一个新线程往服务器端写数据
        new Writer().start();
    }

    /**
     * 写数据线程
     */
    private class Writer extends Thread{

        @Override
        public void run() {
            try{
                //在主线程中 从键盘读取数据输入到服务器端
                Scanner scan = new Scanner(System.in);
                while(scan.hasNextLine()){
                    String line = scan.nextLine();
                    if("".equals(line)){
                        //不允许发空消息
                        continue;
                    }
                    //当前渠道是共用的,发送当前输入数据
                    client.write(charset.encode(line));
                }
                scan.close();
            }catch(Exception e){

            }
        }

    }

    /**
     * 读数据线程
     */
    private class Reader extends Thread {
        @Override
        public void run() {
            try {
                //循环检测
                while(true) {
                    int readyChannels = selector.select();
                    if(readyChannels == 0){
                        continue;
                    }
                    //获取selected所有的事件
                    Set<SelectionKey> selectedKeys = selector.selectedKeys();
                    Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
                    while(keyIterator.hasNext()) {
                        SelectionKey key = (SelectionKey) keyIterator.next();
                        keyIterator.remove();
                        process(key);
                    }
                }
            }
            catch (IOException io){

            }
        }

        /**
         * 根据事件的不同,做不同的处理
         * @param key
         * @throws IOException
         */
        private void process(SelectionKey key) throws IOException {
            //读就绪事件
            if(key.isReadable()){
                //通过key找到对应的通道
                SocketChannel sc = (SocketChannel)key.channel();
                //创建缓存区
                ByteBuffer buff = ByteBuffer.allocate(1024);
                String content = "";
                //读数据
                while(sc.read(buff) > 0){
                    buff.flip();
                    content += charset.decode(buff);
                }
                //打印内容
                System.out.println(content);
                //设置当前为读就绪
                key.interestOps(SelectionKey.OP_READ);
            }
        }
    }
    
    public static void main(String[] args) throws IOException {
        new NIOClient().session();
    }
}

Server:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

/**
 * @ProjectName: onereader
 * @Package: com.onereader.webblog.common.nio
 * @ClassName: NIOServer
 * @Author: onereader
 * @Description: ${description}
 * @Date: 2019/9/1 13:23
 * @Version: 1.0
 */
public class NIOServer {

    private int port = 9999;
    private Charset charset = Charset.forName("UTF-8");
    private Selector selector = null;

    public NIOServer(int port) throws IOException{

        this.port = port;
        //1.打开通道
        ServerSocketChannel server = ServerSocketChannel.open();
        //设置服务端口
        server.bind(new InetSocketAddress(this.port));
        server.configureBlocking(false);
        //2.打开选择器
        selector = Selector.open();
        //注册等待事件
        server.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务已启动,监听端口是:" + this.port);
    }

    /**
     *  监听事件
     * @throws IOException
     */
    public void listener() throws IOException{
        //死循环,这里不会阻塞
        while(true) {
            //1.在轮询获取待处理的事件
            int wait = selector.select();
            System.out.println("当前等待处理的事件:"+wait+"个");
            if(wait == 0){
                //如果没有可处理的事件,则跳过
                continue;
            }
            //获取所有待处理的事件
            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = keys.iterator();
            //遍历
            while(iterator.hasNext()) {
                SelectionKey key = (SelectionKey) iterator.next();
                //处理前,关闭选在择器中的事件
                iterator.remove();
                //处理事件
                process(key);
                System.out.println("事件Readable:"+key.isReadable());
                System.out.println("事件Acceptable:"+key.isAcceptable());
            }
        }

    }

    /**
     * 根据事件类型,做处理
     * @param key
     * @throws IOException
     */
    public void process(SelectionKey key) throws IOException {
        //连接就绪
        if(key.isAcceptable()){
            //获取通道
            ServerSocketChannel server = (ServerSocketChannel)key.channel();
            //进入服务端等待
            SocketChannel client = server.accept();
            //非阻塞模式
            client.configureBlocking(false);
            //注册选择器,并设置为读取模式,收到一个连接请求,
            // 然后起一个SocketChannel,并注册到selector上,
            // 之后这个连接的数据,就由这个SocketChannel处理
            client.register(selector, SelectionKey.OP_READ);
            //将此对应的channel设置为准备接受其他客户端请求
            key.interestOps(SelectionKey.OP_ACCEPT);
            client.write(charset.encode("来自服务端的慰问"));
        }
        //读就绪
        if(key.isReadable()){
            //返回该SelectionKey对应的 Channel,其中有数据需要读取
            SocketChannel client = (SocketChannel)key.channel();

            //往缓冲区读数据
            ByteBuffer buff = ByteBuffer.allocate(1024);
            StringBuilder content = new StringBuilder();
            try{
                while(client.read(buff) > 0){
                    buff.flip();
                    content.append(charset.decode(buff));
                }
                System.out.println("接收到客户端:"+content.toString());
                //将此对应的channel设置为准备下一次接受数据
                key.interestOps(SelectionKey.OP_READ);
            }catch (IOException io){
                key.cancel();
                if(key.channel() != null){
                    key.channel().close();
                }
            }

        }
    }

    public static void main(String[] args) throws IOException {
        new NIOServer(9999).listener();
    }


}

result:

Client:

来自服务端的慰问
请输入要发送服务端的信息:
你好呀

Server:

服务已启动,监听端口是:9999
当前等待处理的事件:1个
事件Readable:false
事件Acceptable:true
当前等待处理的事件:1个
接收到客户端:你好呀
事件Readable:true
事件Acceptable:false

Here with the basics of the above description, and then look at the code you can understand. The whole process of the ~

AIO

Client:

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.CountDownLatch;
/**
 * @ProjectName: onereader
 * @Package: com.onereader.webblog.common.aio
 * @ClassName: AIOClient
 * @Author: onereader
 * @Description: ${description}
 * @Date: 2019/9/1 14:03
 * @Version: 1.0
 */
public class AIOClient {

    private final AsynchronousSocketChannel client ;

    public AIOClient() throws Exception{

        client = AsynchronousSocketChannel.open();
    }

    public void connect(String host,int port)throws Exception{

        //连接服务端
        client.connect(new InetSocketAddress(host,port),null,new CompletionHandler<Void,Void>() {

            /**
             * 成功操作
             * @param result
             * @param attachment
             */
            @Override
            public void completed(Void result, Void attachment) {
                try {
                    client.write(ByteBuffer.wrap(("客户端线程:" + Thread.currentThread().getName()+"请求服务端").getBytes())).get();
                     System.out.println("已发送至服务器");
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }

            /**
             * 失败操作
             * @param exc
             * @param attachment
             */
            @Override
            public void failed(Throwable exc, Void attachment) {
                exc.printStackTrace();
            }
        });

        //读取数据
        final ByteBuffer bb = ByteBuffer.allocate(1024);
        client.read(bb, null, new CompletionHandler<Integer,Object>(){

                    /**
                     * 成功操作
                     * @param result
                     * @param attachment
                     */
                    @Override
                    public void completed(Integer result, Object attachment) {
                        System.out.println("获取反馈结果:" + new String(bb.array()));
                    }

                    /**
                     * 失败操作
                     * @param exc
                     * @param attachment
                     */
                    @Override
                    public void failed(Throwable exc, Object attachment) {
                        exc.printStackTrace();
                    }
                }
        );


        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException ex) {
            System.out.println(ex);
        }

    }

    public static void main(String args[])throws Exception{
        int count = 10;
        final CountDownLatch latch = new CountDownLatch(count);

        for (int i = 0; i < count; i ++) {
            latch.countDown();
            new Thread(){
                @Override
                public void run(){
                    try{
                        latch.await();
                        new AIOClient().connect("localhost",9999);
                    }catch(Exception e){

                    }
                }
            }.start();
        }

        Thread.sleep(1000 * 60 * 10);
    }


}

Server:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;

import static java.util.concurrent.Executors.*;

/**
 * @ProjectName: onereader
 * @Package: com.onereader.webblog.common.aio
 * @ClassName: AIOServer
 * @Author: onereader
 * @Description: ${description}
 * @Date: 2019/9/1 14:04
 * @Version: 1.0
 */
public class AIOServer {


    private final int port;

    public static void main(String args[]) {
        int port = 9999;
        new AIOServer(port);
    }

    /**
     * 注册一个端口,用来给客户端连接
     * @param port
     */
    public AIOServer(int port) {
        this.port = port;
        listen();
    }

    //侦听方法
    private void listen() {
        try {
            //线程缓冲池,为了体现异步
            ExecutorService executorService = newCachedThreadPool();
            //给线程池初始化一个线程
            AsynchronousChannelGroup threadGroup = AsynchronousChannelGroup.withCachedThreadPool(executorService, 1);

            //Asynchronous异步
            final AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open(threadGroup);

            //启动监听
            server.bind(new InetSocketAddress(port));
            System.out.println("服务已启动,监听端口" + port);

            final Map<String,Integer> count = new ConcurrentHashMap<String, Integer>();
            count.put("count", 0);
            //开始等待客户端连接
            //实现一个CompletionHandler 的接口,匿名的实现类
            server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
                //缓存区
                final ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
                //实现IO操作完成的方法
                @Override
                public void completed(AsynchronousSocketChannel result, Object attachment) {
                    count.put("count", count.get("count") + 1);
                    System.out.println(count.get("count"));
                    try {
                        //清空缓存标记
                        buffer.clear();
                        //读取缓存内容
                        result.read(buffer).get();
                        //写模式转换成读模式
                        buffer.flip();
                        result.write(buffer);
                        buffer.flip();
                    } catch (Exception e) {
                        System.out.println(e.toString());
                    } finally {
                        try {
                            result.close();
                            server.accept(null, this);
                        } catch (Exception e) {
                            System.out.println(e.toString());
                        }
                    }
                }

                //实现IO操作失败的方法
                @Override
                public void failed(Throwable exc, Object attachment) {
                    System.out.println("IO操作是失败: " + exc);
                }
            });
            try {
                Thread.sleep(Integer.MAX_VALUE);
            } catch (InterruptedException ex) {
                System.out.println(ex);
            }
        } catch (IOException e) {
            System.out.println(e);
        }
    }


}

result:

Client

已发送至服务器
已发送至服务器
已发送至服务器
已发送至服务器
已发送至服务器
已发送至服务器
已发送至服务器
已发送至服务器
已发送至服务器
已发送至服务器
获取反馈结果:客户端线程:Thread-22请求服务端                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
获取反馈结果:客户端线程:Thread-21请求服务端                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
获取反馈结果:客户端线程:Thread-20请求服务端                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
获取反馈结果:客户端线程:Thread-19请求服务端                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
获取反馈结果:客户端线程:Thread-18请求服务端                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
获取反馈结果:客户端线程:Thread-17请求服务端                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
获取反馈结果:客户端线程:Thread-16请求服务端                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
获取反馈结果:客户端线程:Thread-15请求服务端                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
获取反馈结果:客户端线程:Thread-14请求服务端                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
获取反馈结果:客户端线程:Thread-13请求服务端                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

Server

服务已启动,监听端口9999
1
2
3
4
5
6
7
8
9
10

to sum up

Look at the code to achieve, is not a bunch of text to be more comfortable than watching, I do not want too much here boil complaint, and we all look at the code it -
that's my summary of this, to be honest seen a lot of big brothers wrote thing. It is difficult to understand this thing through text Editor's Note, finally hands-on operation of the following in order to understand.

Guess you like

Origin www.cnblogs.com/one-reader/p/11469554.html