One-stop learning Java network programming comprehensive understanding of BIO_NIO_AIO, learning notes (5)

Hi everybody, I'm方圆


1 Overview

1.1 Translation translation? What is NIO?

NIO: I think the translation is Non-Blockingmore straightforward. Compared with BIO, there is also a comparison. It is best to call him non-blocking IO.

  • It has the following differences from BIO
    Insert picture description here
  • Channel Yes 双向, it can read and write. Compared with Stream, it does not distinguish between input stream and output stream, and Channel can complete non-blocking read and write, as well as block read and write

1.2 Introduction to Buffer

Insert picture description here

  • Channel reading and writing are inseparable from Buffer. Buffer is actually an area in the memory for reading and writing.

1.2.1 Write mode

Insert picture description here

  • Three of the pointers we need to understand positionare the current pointer position, which is limitused in the read mode. It is used to mark the maximum readable range, which capacityis the maximum writable range threshold.

Insert picture description here

When we write data and write four grids, we execute the flip()method, and it can be changed to the 读模式limit pointer directly changed to the limit position of the data we just wrote, and the position pointer returns to the initial position, so that we can read the data out
Insert picture description here

1.2.2 Two switching from read mode to write mode

Insert picture description here

  1. When we have read all the data, switch to the write mode and
    call the clear()method. It will return the position pointer to the initial position and limit back to the farthest end, so that the data can be restarted. Although clear means clear, in fact it Just move the position of the pointer, and does not clear the data, but will overwrite the original position
    Insert picture description here
  2. Read only part of the data, I think part of the reservation will be unread, and now I have to start to write mode of operation, so you can perform the compact()method
    This method 将没有读到的数据保存到初始位置, which position指针的位置将会移动到这些数据的后面位置, after reading the data never started writing data
    Insert picture description here
    after When reading the data again, we can read out the data that was not read last time

1.3 Introduction to Channel

Data exchange between channels all need to rely on Buffer
Insert picture description here

1.3.1 Several important channels

Insert picture description here

  • FileChannel: used for file transfer
  • ServerSocketChannel and SocketChannel: transmission for network programming

2. File copy combat

  • A byte-by-byte copy is really slow.
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

interface FileCopyRunner{
    
    
    void copyFile(File source,File target);
}

public class FileCopyDemo {
    
    

    private static void close(Closeable closeable){
    
    
        if(closeable != null) {
    
    
            try {
    
    
                closeable.close();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
    }

    //不使用任何缓冲的留的拷贝
    private static FileCopyRunner noBufferStreamCopy = new FileCopyRunner() {
    
    
        @Override
        public void copyFile(File source, File target) {
    
    
            InputStream fin = null;
            OutputStream fout = null;
            try {
    
    
                fin = new FileInputStream(source);
                fout = new FileOutputStream(target);
                int result;
                while((result = fin.read()) != - 1){
    
    
                    fout.write(result);
                }
            } catch (FileNotFoundException e) {
    
    
                e.printStackTrace();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }finally {
    
    
                close(fin);
                close(fout);
            }
        }
    };

    //使用缓冲区的流的拷贝
    private static FileCopyRunner bufferStreamCopy = new FileCopyRunner() {
    
    
        @Override
        public void copyFile(File source, File target) {
    
    
            InputStream fin = null;
            OutputStream fout = null;
            try {
    
    
                fin = new FileInputStream(source);
                fout = new FileOutputStream(target);
                //创建缓冲区
                byte[] buffer = new byte[1024];
                int result;
                while((result = fin.read(buffer)) != -1){
    
    
                    //result这里表示从中读出来的具体字节数
                    //虽然缓冲区中能缓存1024,但是我们读取的时候不一定就有这么多字节
                    //所以我们使用result做下面的参数
                    fout.write(buffer,0,result);
                }
            } catch (FileNotFoundException e) {
    
    
                e.printStackTrace();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }finally {
    
    
                close(fin);
                close(fout);
            }
        }
    };

    //使用带有缓冲区的channel复制 nio
    private static FileCopyRunner nioBufferCopy = new FileCopyRunner() {
    
    
        @Override
        public void copyFile(File source, File target) {
    
    
            FileChannel fin = null;
            FileChannel fout = null;

            try {
    
    
                fin = new FileInputStream(source).getChannel();
                fout = new FileOutputStream(target).getChannel();
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

                while(fin.read(byteBuffer) != -1){
    
    
                    byteBuffer.flip();//转变为读模式
                    while (byteBuffer.hasRemaining()){
    
    
                        fout.write(byteBuffer);
                    }
                    byteBuffer.clear();//转变为写模式
                }
            } catch (FileNotFoundException e) {
    
    
                e.printStackTrace();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }finally {
    
    
                close(fin);
                close(fout);
            }
        }
    };

    //使用没有缓冲区的channel复制文件
    private static FileCopyRunner nioTransferCopy = ((source, target) -> {
    
    
        FileChannel fin = null;
        FileChannel fout = null;

        try {
    
    
            fin = new FileInputStream(source).getChannel();
            fout = new FileOutputStream(target).getChannel();

            long transferred = 0L;
            long size = fin.size();
            while(transferred != size){
    
    
                //如果拷贝的大小没有达到源文件的大小就要一直拷贝
                transferred += fin.transferTo(0,size,fout);
            }
        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            close(fin);
            close(fout);
        }
    });

    public static void main(String[] args) {
    
    
        File source = new File("J:\\StudySpace\\Java秒杀系统方案优化-高性能高并发实战\\project.zip");
        File target = new File("J:\\StudySpace\\Java秒杀系统方案优化-高性能高并发实战\\p1.zip");
        File target2 = new File("J:\\StudySpace\\Java秒杀系统方案优化-高性能高并发实战\\p2.zip");
        File target3 = new File("J:\\StudySpace\\Java秒杀系统方案优化-高性能高并发实战\\p3.zip");
        File target4 = new File("J:\\StudySpace\\Java秒杀系统方案优化-高性能高并发实战\\p4.zip");

        new Thread(() -> noBufferStreamCopy.copyFile(source,target)).start();
        new Thread(() -> bufferStreamCopy.copyFile(source,target2)).start();
        new Thread(() -> nioBufferCopy.copyFile(source,target3)).start();
        new Thread(() -> nioTransferCopy.copyFile(source,target4)).start();
    }
}


3. Overview of Selector

  • Channel needs to be registered on Selector
    Insert picture description here
  • At the same time of registration, you must tell the Selector the monitoring status
    Insert picture description here
  • The corresponding states of Channel are:: CONNECTsocketChannel has established a connection with the server;: serverSocketChannel has established a connection ACCEPTwith the client;: READreadable state ;: WRITEwritable state
    Insert picture description here
  • After registration is complete in the Channel Selector, will return a SelectKey objects, which has several important ways: interestOps: View the status of the registered Channel bindings; readyOps: to see which is the operational state; channel: Return channel objects; selector: Return target selector ; attachment: Attach other objectsInsert picture description here
  • Call the select method of the Selector to return the number of events it monitors, which can respond to multiple events at the same time. However, it is a blocking call. When there is no monitoring event that can be used to respond to the request, it will be blocked and will not return until there is an available channel that can respond to the request.
    Insert picture description here

Come on!

Guess you like

Origin blog.csdn.net/qq_46225886/article/details/107499933