Aprendizaje integral de programación de redes Java comprensión integral de BIO_NIO_AIO, notas de aprendizaje (5)

Hola a todos, soy方圆


1. Información general

1.1 Traducción traducción? ¿Qué es NIO?

NIO: Creo que la traducción es Non-Blockingmás sencilla. Comparado con BIO, también hay una comparación. Es mejor llamarlo IO sin bloqueo.

  • Tiene las siguientes diferencias con BIO
    Inserte la descripción de la imagen aquí
  • Canal Sí 双向, puede leer y escribir. En comparación con Stream, no distingue entre el flujo de entrada y el flujo de salida, y el canal puede completar la lectura y escritura sin bloqueo, así como bloquear la lectura y escritura

1.2 Introducción a Buffer

Inserte la descripción de la imagen aquí

  • La lectura y escritura de canales son inseparables de Buffer. Buffer es en realidad un área en la memoria para leer y escribir.

1.2.1 Modo de escritura

Inserte la descripción de la imagen aquí

  • Tres de los punteros que debemos entender positionson la posición actual del puntero, que se limitusa en el modo de lectura. Se usa para marcar el rango máximo de lectura, que capacityes el umbral máximo del rango de escritura.

Inserte la descripción de la imagen aquí

Cuando escribimos datos y escribimos cuatro cuadrículas, ejecutamos el flip()método, y se puede cambiar al 读模式puntero de límite, cambiar directamente a la posición límite de los datos que acabamos de escribir, y el puntero de posición vuelve a la posición inicial, para que podamos leer los datos.
Inserte la descripción de la imagen aquí

1.2.2 Dos cambios del modo de lectura al modo de escritura

Inserte la descripción de la imagen aquí

  1. Cuando hayamos leído todos los datos, cambiamos al modo de escritura y
    llamamos al clear()método. Devolverá el puntero de posición a la posición inicial y se limitará al extremo más lejano, de modo que los datos se puedan reiniciar. Aunque claro significa claro, de hecho Simplemente mueva la posición del puntero y no borra los datos, pero sobrescribirá la posición original
    Inserte la descripción de la imagen aquí
  2. Leer solo parte de los datos, creo que parte de la reserva no se leerá, y ahora tengo que comenzar a escribir el modo de operación, para que pueda realizar el compact()método
    Este método 将没有读到的数据保存到初始位置, que position指针的位置将会移动到这些数据的后面位置, después de leer los datos, nunca comenzó a escribir datos
    Inserte la descripción de la imagen aquí
    después Al leer los datos nuevamente, podemos leer los datos que no se leyeron la última vez

1.3 Introducción al canal

El intercambio de datos entre canales debe depender de Buffer
Inserte la descripción de la imagen aquí

1.3.1 Varios canales importantes

Inserte la descripción de la imagen aquí

  • FileChannel: utilizado para la transferencia de archivos
  • ServerSocketChannel y SocketChannel: transmisión para programación de red

2. Combate de copia de archivo

  • Una copia byte a byte es realmente lenta.
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. Descripción general del selector

  • El canal debe estar registrado en Selector
    Inserte la descripción de la imagen aquí
  • Al mismo tiempo que se registra, debe informar al Selector el estado
    Inserte la descripción de la imagen aquí
  • Los estados correspondientes del canal son :: CONNECTsocketChannel ha establecido una conexión con el servidor ;: serverSocketChannel ha establecido una conexión ACCEPTcon el cliente ;: READestado legible ;: estado WRITEescribible
    Inserte la descripción de la imagen aquí
  • Después de finalizado el registro en el selector de canales, volverá a objetos selectKey, que tiene varias maneras importantes: interestOps: Ver el estado de los enlaces de canal registrados; readyOps: para ver cuál es el estado de funcionamiento; channel: Objetos de canal de retorno; selector: Selector de objetivo de rentabilidad ; attachment: Adjuntar otros objetosInserte la descripción de la imagen aquí
  • Llame al método de selección del Selector para devolver el número de eventos que supervisa, que pueden responder a varios eventos al mismo tiempo. Sin embargo, es una llamada de bloqueo, cuando no hay un evento de monitoreo que pueda usarse para responder a la solicitud, se bloqueará y no regresará hasta que haya un canal disponible que pueda responder a la solicitud.
    Inserte la descripción de la imagen aquí

¡Venga!

Supongo que te gusta

Origin blog.csdn.net/qq_46225886/article/details/107499933
Recomendado
Clasificación