Java BIO, NIO y AIO introducción (el proceso de aprendizaje)

Java BIO, NIO e introducción AIO

Debido a Netty NIO es un marco en el proceso de aprendizaje en Netty, por lo que antes de comenzar. Para un estudio completo realizado en BIO, NIO, AIO.

Recursos para el aprendizaje de las acciones:

Netty aprendizaje: https://www.bilibili.com/video/BV1DJ411m7NR?from=search&seid=8747534277052777648

Netty Fuente: https://www.bilibili.com/video/BV1cb411F7En?from=search&seid=12891183478905555151

Estructuras de Datos y Algoritmos: https://www.bilibili.com/video/BV1E4411H73v?from=search&seid=9508506178445014356

java patrones de diseño: https://www.bilibili.com/video/BV1G4411c7N4?from=search&seid=9508506178445014356

Más recursos se derivan de los datos publicados en los usuarios Bilibili.

de programación Java BIO

BIO - el bloqueo de IO. Que Java IO remoto

modelo IP

imagen-20200324064308021

BIO modelo de subprocesamiento:

imagen-20200324064657688

modelo NIO (breve descripción):

imagen-20200324064946750

imagen-20200324065054666

escenarios modelo IO

imagen-20200324065420911

Java BIO introducción básica

imagen-20200324065937609

mecanismo de Java BIO

imagen-20200324070407477

Aplicaciones Java BIO

imagen-20200324070436188

// 代码示例: 
public class BIOService {
    public static void main(String[] args) throws IOException {
        // 功能需求:
        // 使用BIO模型编写一个服务器,监听6666窗口,当有客户端连接时,就启动一个客户端线程与之通信.
        // 要求使用线程连接机制,可以连接多个客户端.
        // 服务器端可以接受客户端发送的数据(telnet方式即可)

        //1. 首先建立一个线程池.
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();

        //2. 建立一个监听服务,来监听客户端连接
        ServerSocket serverSocket = new ServerSocket(6666);
        System.out.println("服务器启动成功");

        while (true) {
            // 监听,等待客户端连接
            final Socket socket = serverSocket.accept();
            System.out.println("客户端连接了.");
            //连接了之后,给这个用户创建一个线程用于通信.
            newCachedThreadPool.execute(new Runnable() {
                public void run() {
                    //从写run方法. 接受客户端发送的消息.打印到控制台.
                    handler(socket);
                }
            });
        }
    }

    private static void handler(Socket socket) {
        byte[] bytes = new byte[1024];

        try (InputStream inputStream = socket.getInputStream()) {
            while (true) { //通过socket获取到输入流
                int read = inputStream.read(bytes);
                if (read != -1) { // 如果在读的过程中,打印出字节.
                    System.out.println(Arrays.toString(bytes));
                } else {//读完之后,退出循环
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 我试试会报错不会.不关闭流,但是实用的try- which - resource
            System.out.println("关闭连接");
        }

    }
}

Análisis BIO Java

imagen-20200324073443146

de programación Java NIO

JavaNIO introducción básica

imagen-20200324194302794

Canal corresponde en NIO entre ServerSocket BIO. Sin bloqueo se consigue mediante Buffer.

imagen-20200324195031653

NIO Buffer的基本使用 案例介绍:
  public class BasicBuffer {
    public static void main(String[] args) {

        IntBuffer intBuffer = IntBuffer.allocate(5);
        intBuffer.put(1);
        intBuffer.put(2);
        intBuffer.put(3);
        intBuffer.put(4);
        intBuffer.put(5);

        intBuffer.flip();   // 转换读写操作.

        while (intBuffer.hasRemaining()) {
            int i = intBuffer.get();
            System.out.println(i);
        }
    }
}

Comparar la NIO y BIO

imagen-20200324200312784

NIO esquemática tres principios básicos

imagen-20200324201903336

Descripción Selector, Channel Buffer y el diagrama de relación de

  1. Cada canal corresponderá a un Buffer
  2. Selector corresponderá a un hilo. Una pluralidad de hilo correspondiente al canal (conector)
  3. Esta cifra refleja tres de registro a la selección del canal.
  4. Cambia a qué canal, se determina por el evento. Evento es un concepto importante. (Seguimiento tendrá que aprender qué eventos)
  5. selector basado en diferentes eventos, cada canal está encendido.
  6. Buffer es un bloque de memoria, hay una matriz subyacente
  7. la escritura de datos leídos por Buffer, BIO y esto es esencialmente diferente. En términos de flujo para un BIO, ya sea un flujo de entrada o una corriente de salida, no un flujo de dos vías. Pero la memoria intermedia NIO puede leer, también se puede escribir. Pero se requiere el uso de interruptor de modo Flip ().
  8. Canalizar en ambos sentidos. La reacción puede ser el caso donde el sistema operativo subyacente. Por ejemplo, Linux, a través de al sistema operativo subyacente es bi-direccional.

NIO de tres núcleos -Buffer

Buffer introducción básica

imagen-20200324204652205

clase Buffer y su API subclases

imagen-20200324204938332

imagen-20200324205035963

imagen-20200324205428253

API de búfer

imagen-20200324210255934

API ByteBuffer

imagen-20200324210417873

NIO de tres núcleos -Canal

introducción básica

imagen-20200324210817081

imagen-20200324210832533

imagen-20200324211625594

ServerSocketChannel ServerSocket similares

Similar ServerChannel servidor

clase FileChannel: Ejemplo

imagen-20200324211454874

imagen-20200324211906709

Lograr diagrama de flujo:

imagen-20200325054514787

1. 应用实例: 本地文件写数据。 代码实现:
  public class NIOFileBuffer {
    public static void main(String[] args) throws IOException {
        //将"hello,二娃"写入到hello.txt文件中
        String str = "hello,二娃";

        // 首先要创建一个输出流:
        FileOutputStream fileOutputStream = new FileOutputStream("hello.txt");

        //创建一个fileChannel通道
        FileChannel fileOutputStreamChannel = fileOutputStream.getChannel();

        //创建一个ByteBuffer,将字符串写入到Buffer中
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        byteBuffer.put(str.getBytes());

        //要对byteBuffer进行一个翻转
        byteBuffer.flip();

        //将byteBuffer写入到fileChannel中
        fileOutputStreamChannel.write(byteBuffer);

        //关闭流
        fileOutputStream.close();

    }
}
2. 本地文件读数据:  
  
  			//创建一个输入流,读取文件内容
        File file = new File("hello.txt");
        FileInputStream fileInputStream = new FileInputStream(file);

        //获取到输入流通到
        FileChannel fileInputStreamChannel = fileInputStream.getChannel();
        //准备一个byteBuffer
        ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length());

        //将管道中的数据放入到byteBuffer中
        fileInputStreamChannel.read(byteBuffer);

        //输出内容
        System.out.println(new String(byteBuffer.array()));
        fileInputStream.close();

imagen-20200325055802774

imagen-20200325055918597

3. 使用一个Buffer完成文件的读取。   把文件A中的内容读取到,写入到文件B中。 示意图如上.代码如下:
   //用一个Buffer完成文件的读写
try (
      FileInputStream fileInputStream = new FileInputStream(new File("hello.txt"));
      FileChannel fileInputStreamChannel = fileInputStream.getChannel();

      FileOutputStream fileOutputStream = new FileOutputStream(new File("hello2.txt"));
      FileChannel fileOutputStreamChannel = fileOutputStream.getChannel();
	) {
            ByteBuffer byteBuffer = ByteBuffer.allocate(512);

            while (true) {
                byteBuffer.clear();
                int read = fileInputStreamChannel.read(byteBuffer);
                if (read == -1) {
                    break;
                }
                byteBuffer.flip();
                fileOutputStreamChannel.write(byteBuffer);
            }
        }

imagen-20200325062138368

4. 拷贝文件。使用transferFrom方法
  try(
        // 使用拷贝方法,拷贝一个图片
        FileInputStream fileInputStream = new FileInputStream(new File("hello.txt"));
        FileChannel fileInputStreamChannel = fileInputStream.getChannel();

        FileOutputStream fileOutputStream = new FileOutputStream(new File("hello2.txt"));
        FileChannel fileOutputStreamChannel = fileOutputStream.getChannel();

        ){
          fileOutputStreamChannel.transferFrom(fileInputStreamChannel,0,fileInputStreamChannel.size());
        }

Notas y detalles acerca de búfer y el Canal

imagen-20200325063022599

La precaución debe prestar atención.

1. Buffer支持类型化。 put的什么类型,读取的时候就要get相应的类型。 举例说明:
   public static void main(String[] args) {

        ByteBuffer byteBuffer = ByteBuffer.allocate(64);
        byteBuffer.putInt(123);
        byteBuffer.putChar('a');
        byteBuffer.putLong(10L);
        byteBuffer.putShort((short)234);

        byteBuffer.flip();

        System.out.println(byteBuffer.getInt());
        System.out.println(byteBuffer.getChar());
        System.out.println(byteBuffer.getLong());
        System.out.println(byteBuffer.getShort());   
  //顺序如果不同,可能会导致程序抛出异常。java.nio.BufferUnderflowException

 }
2. 可以将一个普通Buffer转成只读Buffer。只读Buffer只能读。写操作时会抛 ReadOnlyBufferException 
  举例说明:
  public static void main(String[] args) {
        ByteBuffer byteBuffer = ByteBuffer.allocate(32);
        for (int i = 0; i < byteBuffer.capacity(); i++) {
            byteBuffer.put((byte) i);
        }
        byteBuffer.flip();

        ByteBuffer asReadOnlyBuffer = byteBuffer.asReadOnlyBuffer();
        while (asReadOnlyBuffer.hasRemaining()) {
            System.out.print(asReadOnlyBuffer.get()+ " ");
        }

        asReadOnlyBuffer.put((byte) 12); //已经转换成readBuffer。此时pur会抛异常ReadOnlyBufferException
    }

imagen-20200325071840961

3. MappedByteBuffer 
  作用: 可让文件直接在内部(堆外内存)修改,操作系统不需要拷贝一次。
  
  // 参数1. FileChannel.MapMode.READ_WRITE 使用的读写模式
  // 参数2 : 0 可以直接修改的起始位置
  // 参数3 : 5 是映射到内存的大小(不是索引位置)。即将1.txt的多少个字节映射到内存
  //可以直接修改的范围就是0-5 
  // MappedByteBuffer 的实际类型是 DirectByteBuffer
  
  public static void main(String[] args) throws Exception {
        try(
        // 获取到一个文件, rw为可以读写的模式
        RandomAccessFile randomAccessFile = new RandomAccessFile("hello.txt","rw");
        FileChannel fileChannel = randomAccessFile.getChannel();
        ) {
            MappedByteBuffer map = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, 5);
            map.put(1, (byte) 'H');
            map.put(2, (byte) 'E');
            map.put(3, (byte) 'E');
        }
    }
4. Scattering 和 Gathering ; 分散和聚合。
  之前我们都是使用一个Buffer来操作的。NIO还支持多个Buffer(即Buffer数组)来完成读写操作。即 分散和聚合。
  
 //Scattering 将数据写入到Buffer时,可以采用Buffer数组,依次写入。[分散]
 //Gathering  从Buffer读取数据时,可以采用Buffer数组,依次读【聚合】
  
 //这次使用 ServerSocketChannel 和 SocketChannel 网络 来操作。
  
   public static void main(String[] args) throws IOException {

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        InetSocketAddress inetSocketAddress = new InetSocketAddress(7000);

        // 绑定端口到socket ,并启动
        serverSocketChannel.socket().bind(inetSocketAddress);
        // 创建一个Buffer数组
        ByteBuffer[] byteBuffers = new ByteBuffer[2];
        byteBuffers[0] = ByteBuffer.allocate(5);
        byteBuffers[1] = ByteBuffer.allocate(3);

        //等待客户端连接(使用telnet)
        SocketChannel socketChannel = serverSocketChannel.accept();
        System.out.println("连接成功");
        long messageLength = 8;

        //连接成功,循环读取
        while (true) {
            int byteRead = 0;
            while (byteRead < messageLength) {
                long l = socketChannel.read(byteBuffers);
                byteRead += l;
                System.out.println("当前的byteRead: " + byteRead);

                //使用流打印,打印出当前的Buffer中的  limit , position
                Arrays.stream(byteBuffers).map(byteBuffer -> "position" + byteBuffer.position() + ", limit "
                        + byteBuffer.limit()).forEach(System.out::println);
            }

            //将所有的Buffer进行flip
            Arrays.stream(byteBuffers).map(ByteBuffer::flip);

            //将数据读出返回给客户端
            long byteWrite = 0;
            while (byteWrite < messageLength) {
                long write = socketChannel.write(byteBuffers);
                byteWrite += write;
            }

            //将所有的BUffer进行clean
            Arrays.stream(byteBuffers).map(ByteBuffer::clear);

            System.out.println("readLength " + byteRead + "writeLength " + byteWrite);
        }
    }

-Selector tres núcleos de NIO

Selector de introducción básica

imagen-20200326081250576imagen-20200326081453102

API selector

Método clase selector y funcionalidad descrita método implementado. funciones enumeradas, más cómodo de usar.

Recuerde que debe centrarse - método abierto devuelve un selector.

imagen-20200326081819684

imagen-20200326082842680

NIO no bloqueante red programación principio cuadro de análisis

La descripción de la figura:

  1. Cuando la conexión del cliente será a través de la correspondiente SocketChannel serverSocketChannel
  2. escucha selector (usando el método Select), con un pasaje devuelve el número de eventos.
  3. El SocketChannel registrado al selector. Un selector puede registrar varios SocketChannel. (SelectableChannel.register (sel Selectoe, ops int)). ops parámetros descritos: Hay cuatro estados.
  4. Después de registrar una SelectionKey de retorno, lo hará (la forma en que un conjunto de relacionado) y el selector asociado.
  5. Además cada SelectionKey (un evento ocurrió SelectionKey)
  6. Entonces adquisición inversa SocketChannel registrado a través SelectionKey. (Usando SelectionKey.channel () método)
  7. Usted puede obtener canales, procesos de negocio completos.

imagen-20200326082955466

imagen-20200327041758862

实例代码案例演示:   NIO非阻塞网络编程通讯
  
服务器端:
  public static void main(String[] args) throws IOException {
        // NIO非阻塞网络编程通讯  -- 服务器端
//        1. 创建serverSocketChannel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//        2. 得到一个Selector对象
        Selector selector = Selector.open();
//        3. 绑定一个端口6666, 在服务器端监听
        serverSocketChannel.socket().bind(new InetSocketAddress(6666));
//        4. 设置为非阻塞
        serverSocketChannel.configureBlocking(false);
//        5. 把serverSocketChannel注册到Selector,关心事件op_accept
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
//        6. 循环等待客户端连接
        while (true) {
            // 等待一秒钟,如果没有客户端事件发生,不等待了。
            if ((selector.select(1000) == 0)) {
                //没有事件发生
                System.out.println("服务器上一秒中,没有客户端连接");
                continue;
            }
            // 如果返回的>0 ,就获取到相关的 selectionKeys集合。
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
            // 通过selectionKeys反向获取通道,处理业务
            while (selectionKeyIterator.hasNext()) {
                // 获取selectionKey
                SelectionKey selectionKey = selectionKeyIterator.next();
                // 根据key对应的通道事件,做相应的处理
                if (selectionKey.isAcceptable()) {
                    //给此客户端分配一个socketChannel
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    System.out.println("客户端连接了, " + selectionKey.hashCode());
                    socketChannel.configureBlocking(false);
                    //将此channel注册到 selector上, 关注read事件
                    socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                }
                if (selectionKey.isReadable()) { //发生了 read事件
                    //通过key,反向获取到对应的channel
                    SocketChannel channel = (SocketChannel) selectionKey.channel();
                    //获取到该key的buffer
                    ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();
                    channel.read(byteBuffer);
                    System.out.println("from 客户端 : " + new String(byteBuffer.array()));
                }
                //手动移除key
                selectionKeyIterator.remove();
            }
        }
    }


客户端:
public static void main(String[] args) throws IOException {
//        1. 得到一个网络通道
        SocketChannel socketChannel = SocketChannel.open();
//        2. 提供非阻塞
        socketChannel.configureBlocking(false);
//        3. 提供服务器端的IP和端口
        InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 6666);
//        4. 连接服务器
        if (!socketChannel.connect(inetSocketAddress)) {
            //        连接不成功, 打印一句话,代表这时候不阻塞,可以去做别的事情
            while (!socketChannel.finishConnect()) {
                System.out.println("客户端连接未成功,先去干别的事情了");
            }
        }
//        5. 如果连接成功,发送数据。 通过ByteBuffer.wrap (根据字节的大小自动放入到Buffer中。)
        String str = "hello,二娃";
        ByteBuffer byteBuffer = ByteBuffer.wrap(str.getBytes());
//        6. 发送数据。将Buffer数据写入channel。
        socketChannel.write(byteBuffer);

        System.in.read();
    }
API SelectionKey

Cada registro de un cliente, habrá un nuevo canal, selectionkey.keys () aumentará 1

selectionKeys.size (); el número de la actividad del canal.

El número total de la canal; selectionkeys.keys ().

imagen-20200327054411919

Tenga en cuenta que esta vez miré el código fuente, la implementación real de selector tiene vídeo y maestro no es lo mismo.

A continuación se muestra mi propio método y de vídeo maestro comparar. La razón es que el ordenador del profesor es Windows, tengo un Mac

imagen-20200327054921967

imagen-20200327054758287

imagen-20200327055507664

API ServerSocketChannel

imagen-20200327055738707

API SocketChannel

imagen-20200327060030339

Ejemplos de aplicación NIO programación de la red - un sistema de chat de grupo

sistema de chat de grupo Código de finalización Caso Este

imagen-20200327060524695

开发流程:
1. 先编写服务器端
  1.1 服务器启动并监听6667 
  1.2 服务器接受客户端信息,并实现转发【处理上线和离线】
2.编写客户端
  2.1 连接服务器
  2.2 发送消息
  2.3 接受服务器的消息
  
  1.初始化构造器,
  2. 监听
服务器端代码: 
  
/**
 * weChat服务器端
 * 1. 先编写服务器端
 *   1.1 服务器启动并监听6667
 *   1.2 服务器接受客户端信息,并实现转发【处理上线和离线】
 */
public class weCharServer {
    private ServerSocketChannel listenSocketChannel ;
    private Selector selector;
    private static  final  int PORT = 6666;

    public weCharServer() throws IOException {
        //1. 得到选择器
        selector = Selector.open();
        //2. 得到 serverSocketChannel
        listenSocketChannel = ServerSocketChannel.open();
        //3. 绑定端口
        listenSocketChannel.socket().bind(new InetSocketAddress(PORT));
        //4. 设置非阻塞
        listenSocketChannel.configureBlocking(false);
        //5. 注册
        listenSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    }

    /**
     * 监听
     */
    public void listen(){
        try {
        while (true) {
                int count = selector.select(2000);
            if (count > 0) {
                //有事件处理
                //遍历得到selectionKeys集合
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    //取出selectionKey
                    SelectionKey key = iterator.next();
                    //监听到accept
                    if (key.isAcceptable()) {
                        SocketChannel sc = listenSocketChannel.accept();
                        //将 该 SocketChannel注册到 selector 上
                        sc.configureBlocking(false);
                        sc.register(selector, SelectionKey.OP_READ);
                        //提示上线
                        System.out.println(sc.getRemoteAddress() + "上线了");
                    }
                    if (key.isReadable()) {
                        //通道发送read事件,即通道是刻度的状态
                        keyRead(key);
                    }

                    iterator.remove();
                }
            }

        }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void keyRead(SelectionKey key) {
        SocketChannel channel = null;
        try {

            //根据key得到channel
            channel = (SocketChannel) key.channel();
            //创建Buffer
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int read = channel.read(buffer);
            //根据read只,做处理
            if (read > 0) {
                //把缓存区的数据转成字符串
                String msg = new String(buffer.array());
                System.out.println("from 客户端 : " + msg);
                //向其他客户转发消息
                sendInfoToOtherClient(msg,channel);
            }
        } catch (Exception e) {
            try {
                System.out.println(channel.getRemoteAddress() + " 离线了");
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    private void sendInfoToOtherClient(String msg, SocketChannel self) throws IOException {
        System.out.println("服务器转发消息中...");
        //遍历所有注册到selector上的socketChannel,并排除self
        for (SelectionKey key : selector.keys()) {
            //通过key取出对应的socketChannel
            SelectableChannel targetChannel = key.channel();
            //排除自己
            if (targetChannel instanceof SocketChannel && targetChannel != self) {
                //将Buffer中的数据写入通道
                ((SocketChannel) targetChannel).write(ByteBuffer.wrap(msg.getBytes()));
            }

        }
    }

    public static void main(String[] args) throws IOException {
        weCharServer weCharServer = new weCharServer();
        weCharServer.listen();
    }
}

客户端代码:
  
public class weChatClient {
    private SocketChannel socketChannel;
    private String username;
    private Selector selector;

    public weChatClient() throws IOException {
        selector = Selector.open();
        socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 6666));
        //设置为非阻塞
        socketChannel.configureBlocking(false);
        //注册
        socketChannel.register(selector, SelectionKey.OP_READ);
        username = socketChannel.getLocalAddress().toString().substring(1);
        System.out.println("username : " + username);
    }

    //向服务器发送消息
    public void senInfo(String info) {
        info = username + " 说 : " + info;
        try {
            socketChannel.write(ByteBuffer.wrap(info.getBytes()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //从服务器读取消息
    public  void readInfo(){
        try {
            int readChannels = selector.select();
            if (readChannels > 0) {
                //有可用的通道
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    if (key.isReadable()) { //读事件
                        //得到相关的通道
                        SocketChannel sc = (SocketChannel) key.channel();
                        //得到一个缓冲区
                        ByteBuffer allocate = ByteBuffer.allocate(1024);
                        sc.read(allocate);
                        //把读取的数据转换成字符换
                        String msg = new String(allocate.array());
                        System.out.println(msg.trim());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        //启动一个客户端
        weChatClient chatClient = new weChatClient();
        //启动一个线程,每三秒读取从服务器发送的数据
        new Thread(() -> {
            while (true) {
                chatClient.readInfo();
                try {
                    Thread.currentThread().sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        //发送消息给服务器端
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            chatClient.senInfo(scanner.nextLine());
        }
    }

}

NIO y copia cero

Copia cero, es por el aspecto del sistema operativo, sin copia de la CPU.

¿Qué es DMA (acceso directo a memoria)? copia de memoria directa (NA CPU).

imagen-20200327080820783

IO tradicional de lectura y escritura de datos

imagen-20200327080918158

¿Qué es DMA (acceso directo a memoria)? copia de memoria directa (CPU NA)

Tradicional IO: 4 veces utilizando copiar, convertir tres estados.

imagen-20200330055351763

optimización mmap

optimización mmap: El uso de tres copias, interruptor de tres estados.

imagen-20200327081247142

optimización sENDFILE

SENDFILE optimización: Uso 3 copias, interruptor de estado dos veces.

imagen-20200327081423380

SENDFILE una mayor optimización: Use 2 copias, Estado de conmutación contexto dos veces.

Aquí hay unas copias de la CPU. Desde el búfer del núcleo -.> Socket búfer copias de la información, pero rara vez. Tales como la longitud, offet, bajo consumo, puede ser ignorada.

imagen-20200327081641733

imagen-20200327082003728

La diferencia entre mmap y SENDFILE

imagen-20200327082159901

caso copia cero NIO

imagen-20200327082352436

transferTo注意事项 :
  1. 在Linux下,一个transferTo方法就可以传输完、
  2. 在Windows下一次调用transferTo只能传输8M,而且要注意传输时的位置。
  
  使用方法: 
  fileChannel.transferTo(0,fileChannel.size(),socketChannel); 从0开始传,传多少个。

imagen-20200330052903628

de programación Java AIO

imagen-20200330055046252

BIO, NIO, comparación AIO

imagen-20200330055230238

Supongo que te gusta

Origin www.cnblogs.com/wobushitiegan/p/12596351.html
Recomendado
Clasificación