One stop learning Java network programming - learning notes

Keywords: Java NIO

1. General

1.1 what is NIO?

NIO: I think it is translated into non blocking, which is more popular and straightforward. Compared with BIO, there is also a comparison. It is best to call it non blocking IO

  • It has the following differences from BIO
  • Channel is bidirectional, that is, it can read and write. Compared with Stream, it does not distinguish between input Stream and output Stream, and channel can complete non blocking reading and writing as well as blocking reading and writing

1.2 introduction to buffer

  • The reading and writing of the Channel is inseparable from the Buffer, which is actually an area of memory used for reading and writing.

1.2.1 write mode

  • Among the three pointers, we need to know that position is the current pointer position, limit is used for read mode, which is used to mark the maximum readable range, and capacity is the maximum writable range threshold

When we write data and write four grids, we execute the flip() method to change to the read mode. The limit pointer directly changes to the limit position where we just wrote the data, and the position pointer returns to the initial position, so that we can read the data  

1.2.2 switching from read mode to write mode  

 

  1. When we have read all the data, we switch to write mode
    Call the clear() method, which will return the position pointer to the initial position and the limit to the farthest end, so that you can restart the data. Although clear means to clear, in fact, it only moves the position of the pointer and does not clear the data, but will overwrite the original position
  2.   Read only part of the data. I want to keep the unread part. Now I want to start the write mode operation first, so that I can execute the compact() method
    This method will save the unread data to the initial position, and the position pointer will move to the back of these data. After the unread data, start writing data

    When we read the data later, we can read the data we didn't read last time

1.3 introduction to channel

Data exchange between channels depends on Buffer

1.3.1 several important channels

 

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

 

2. Document copying practice  

  • Copy byte by byte 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();
            }
        }
    }

    //Reserved copy without any buffer
    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);
            }
        }
    };

    //A copy of the stream using the buffer
    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);
                //Create buffer
                byte[] buffer = new byte[1024];
                int result;
                while((result = fin.read(buffer)) != -1){
                    //result here indicates the specific number of bytes read from
                    //Although 1024 bytes can be cached in the buffer, we don't necessarily have so many bytes when reading
                    //So we use result as the following parameters
                    fout.write(buffer,0,result);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                close(fin);
                close(fout);
            }
        }
    };

    //Copy nio using channel with buffer
    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();//Change to read mode
                    while (byteBuffer.hasRemaining()){
                        fout.write(byteBuffer);
                    }
                    byteBuffer.clear();//Change to write mode
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                close(fin);
                close(fout);
            }
        }
    };

    //Copy files using channel without buffer
    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){
                //If the size of the copy does not reach the size of the source file, it must be copied all the time
                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 Second kill system scheme optimization-High performance and high concurrency\\project.zip");
        File target = new File("J:\\StudySpace\\Java Second kill system scheme optimization-High performance and high concurrency\\p1.zip");
        File target2 = new File("J:\\StudySpace\\Java Second kill system scheme optimization-High performance and high concurrency\\p2.zip");
        File target3 = new File("J:\\StudySpace\\Java Second kill system scheme optimization-High performance and high concurrency\\p3.zip");
        File target4 = new File("J:\\StudySpace\\Java Second kill system scheme optimization-High performance and high concurrency\\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. Selector overview

  • The Channel needs to be registered on the Selector
  • While registering, tell the Selector the listening status
  • The corresponding states of the Channel are: CONNECT: the state that the socketChannel has established a connection with the server; ACCEPT: serverSocketChannel has established a connection with the client; READ: readable status; WRITE: writable status
  • After the channel is registered on the selector, a SelectKey object will be returned. There are several important methods: interestOps: view the status of the registered channel binding; readyOps: view the operable status; Channel: returns the channel object; Selector: returns the selector object; attachment: attaching objects
  • Call the select method of the Selector, return the number of events it listens to, and respond to multiple events at the same time. However, it is a blocking call. When there is no response to the request in the monitored event, it will be blocked and will not return until there is an available channel to respond to the request

 

 

Posted by bwcc on Thu, 07 Oct 2021 14:22:14 -0700