Serie de explicación detallada del principio de Netty (1) --- Buffer & Chanel en NIO

1. Información general

En la API BIO, la entrada y la salida se realizan a través de dos flujos, InputStream y outPutStream. NIO utiliza un canal de comunicación bidireccional en lugar de ellos. El canal (Channel) debe depender del búfer (búfer) para lograr la comunicación.

El flujo de comparación de la canalización tiene más funciones, como no bloqueo, asignación de memoria fuera del montón y copia cero.

 

2. Definición de búfer

La canalización depende del búfer, así que primero introduzcamos el concepto y el uso del búfer.

Se mantiene una matriz dentro del búfer para almacenar datos. El búfer no admite ningún tipo de datos almacenados, solo se pueden almacenar algunos tipos de datos básicos.

Tiene las funciones de leer y escribir y vaciar. Sin seguridad de subprocesos, debe controlar la seguridad de subprocesos usted mismo.

Ofrezca a todos un beneficio para recibir un mapa de habilidades de arquitectura Java gratuito. Tenga en cuenta que es gratis 

Gratis para recibir el + V requerido para recibir

3. Estructura interna del amortiguador

Tome ByteBuffer, por ejemplo, es una subclase de Buffer, que se utiliza para almacenar datos de tipo Byte, otros búferes son similares, pero los tipos de datos almacenados son diferentes.

Una matriz de bytes se mantiene internamente para almacenar datos.

El búfer de la clase padre tiene 4 atributos importantes:

  • capacidad

    Indica el tamaño de la matriz.

  • límite

    Limite el rango de lectura y escritura del búfer, el valor predeterminado es igual a la capacidad

  • posición

    La posición actual de lectura y escritura, el valor predeterminado es 0, cada vez que se lee un bit o se escribe un bit, +1.

  • marca

    Haga una marca de reinicio para establecer la posición en esta posición. El valor predeterminado es -1

La relación de posición de los cuatro: marca <= posición <= límite <= capacidad

4. Almacenar operaciones de uso común

4.1 asignar

Asigne el espacio de almacenamiento del búfer e inicialice todos los atributos. P.ej:

Inserte la descripción de la imagen aquí
Los resultados obtenidos son los siguientes:
Inserte la descripción de la imagen aquí

4.2 envoltura

Empaquetar un búfer basado en una matriz, la posición es 0, el límite es el valor de capacidad

El código de prueba es el siguiente:

Inserte la descripción de la imagen aquí
Los resultados del búfer son los siguientes:

Inserte la descripción de la imagen aquí

4.3 poner

Escriba en el búfer, el código de prueba es el siguiente:

Inserte la descripción de la imagen aquí

En el proceso de put, se cambiará la posición, es decir, cada vez que se escriba un número, la posición será +1. Cuando se escriba la séptima, la posición superará el límite límite, y en este momento se lanzará una excepción BufferOverflowExeception
Inserte la descripción de la imagen aquí

4.4 voltear

Prepárese para la lectura. Después de poner, ejecute el giro para restablecer la posición y ajústelo a 0.

La siguiente operación de lectura comienza desde la posición.

El código de prueba es el siguiente:

Inserte la descripción de la imagen aquí
El resultado del búfer después de que se ejecuta la colocación 5 es el siguiente:

Inserte la descripción de la imagen aquí
Luego ejecute flip, los resultados son los siguientes:
Inserte la descripción de la imagen aquí
De acuerdo con los resultados, puede ver el rol de flip, establecer la posición en 0

Y el límite se establece en la posición original, el límite en este momento limita el alcance de la lectura.

4.5 obtener

Lea el contenido del búfer, cada vez que lea uno, mueva una posición después de la posición

El código de prueba es el siguiente:

Inserte la descripción de la imagen aquí

Cuando se lee el quinto, el contenido del búfer en este momento es el siguiente: Se
Inserte la descripción de la imagen aquí
puede encontrar que la posición en este momento ha alcanzado el límite del límite. Si lo vuelve a leer, informará un error, lea la excepción fuera de los límites BufferUnderflowException
Inserte la descripción de la imagen aquí

4.6 marca

Establecer el bit de marca y registrar la posición actual

El código de prueba es el siguiente:

Inserte la descripción de la imagen aquí

Después de ejecutar la marca, establezca la propiedad de la marca en posición, es decir, haga una marca
Inserte la descripción de la imagen aquí

4.7 reiniciar

La función de reinicio es establecer el valor de la posición a marcar para modificar un dato en el búfer. O leer un dato en el búfer repetidamente.

El código de prueba es el siguiente:
Inserte la descripción de la imagen aquí

Después de ejecutar el reinicio, los resultados del búfer son los siguientes

Inserte la descripción de la imagen aquí

Después de grabar la marca de la marca, lee dos números y modifica los dos números. Después del reinicio, la posición vuelve a la posición registrada por la marca. En este momento, si escribe de nuevo, puede modificar los dos números en el búfer. El resultado es el siguiente

Inserte la descripción de la imagen aquí

4.8 claro

Restablece los atributos del búfer, pero no borrará los datos en el búfer

Establezca la posición de la posición en 0, la marca en -1. El límite se establece en la capacidad

El código de prueba es el siguiente:

Inserte la descripción de la imagen aquí

Después de ejecutar clear, el resultado del búfer es el siguiente:

Inserte la descripción de la imagen aquí

4.9 rebobinar

Prepárese para volver a leer. Establezca la posición en 0 y el límite sin cambios. la marca se establece en -1

El código de prueba es el siguiente: Después de
Inserte la descripción de la imagen aquí
ejecutar el rebobinado, los resultados del búfer son los siguientes:
Inserte la descripción de la imagen aquí

4.10 restantes

Cuántos rangos legibles se devuelven

Cuál es posición límite

El código de prueba es el siguiente:
Inserte la descripción de la imagen aquí
En este momento, el límite es igual a 5. Después de leer dos veces, se ejecuta el método restante y el resultado devuelto es 3, lo que indica el contenido legible restante

5. chanel

Las tuberías se utilizan para conectar archivos, enchufes de red, etc. Puede realizar lectura y escritura de dos operaciones de E / S al mismo tiempo. Se llama tubería de dos vías. Tiene dos estados: conectado y cerrado. Está abierto cuando se crea la tubería. Una vez cerrado, informará cuando se llame a la operación de E / S. ClosedChannelException . Se isOpen puede juzgar si está en estado abierto mediante el método de canalización .

5.1 Canalización de archivos FileChannel

El nombre sólido sugiere que se utiliza para manipular archivos. Además de las operaciones normales, también admite las siguientes funciones:

  • Soporte para leer y escribir en el área especificada del archivo

  • Mapeo de memoria fuera del montón, al leer y escribir archivos grandes, se puede mapear directamente desde la memoria declarada de JVM para mejorar la eficiencia de lectura y escritura.

  • La tecnología de copia cero, a través de  transferFrom o transferTo directamente la transmisión de datos a un canal, mejora considerablemente el rendimiento.

  • Bloquear el área designada del archivo para evitar que otros programadores accedan a él

Open FileChannel solo se puede abrir a través del flujo en la actualidad, como inputStream.getChannel () y outputStream.getChannel (), solo se puede acceder a la canalización abierta a través del flujo de entrada y solo se puede escribir el outputStream abierto. De lo contrario, NonWritableChannelException y NonReadableChannelException se lanzarán por separado.

Si desea que la tubería admita tanto lectura como escritura, debe usar el modo de RandomAccessFile lectura y escritura.

El siguiente código de prueba es el uso básico de la canalización de archivos

				//1. 打开文件管道
        FileChannel channel = new RandomAccessFile(file_name,"rw").getChannel();

        ByteBuffer buffer=ByteBuffer.allocate(1024); // 声明1024个空间
        // 从文件中 读取数据并写入管道 再写入缓冲 channel.read(buffer); buffer.flip();//上面学的,写完之后,需要将position归0,为了后面的读取做准备 byte[] bytes= new byte[buffer.remaining()]; int i =0; while (buffer.hasRemaining()){ bytes[i++]= buffer.get(); } System.out.println(new String(bytes)); // 把缓冲区数据写入到管道 channel.write(ByteBuffer.wrap("森林大帅哥".getBytes())); channel.close(); 

 

5.2 Tubería de conexión UDP DatagramChannel

UDP es un protocolo sin conexión y DatagramChannel proporciona servicios para que este protocolo reciba mensajes de los clientes.

El uso básico de DatagramChannel es el siguiente:

public void test1() throws IOException { DatagramChannel channel=DatagramChannel.open(); // 绑定端口 channel.bind(new InetSocketAddress(8080)); ByteBuffer buffer=ByteBuffer.allocate(8192); while (true){ buffer.clear(); // 清空还原 channel.receive(buffer); // 阻塞 buffer.flip(); byte[] bytes=new byte[buffer.remaining()]; buffer.get(bytes); System.out.println(new String(bytes)); } } 

 

Utilice el comando nc-uv 127.0.0.1 8080 para enviar udp al número de puerto IP especificado

Inserte la descripción de la imagen aquí
La consola de ideas generará el siguiente resultado:

Inserte la descripción de la imagen aquí

5.3 Tubería de conexión TCP

TCP es un protocolo de conexión y la comunicación solo se puede realizar una vez establecida la conexión. Esto requiere las siguientes dos canalizaciones:

  • ** ServerSocketChannel: ** Se utiliza para establecer una conexión con el cliente.

  • ** SocketChannel: ** Se usa para leer y escribir mensajes con el cliente

El código de prueba es el siguiente:

@Test
public void test1() throws IOException { // 用于与客户端建立连接 ServerSocketChannel channel = ServerSocketChannel.open(); channel.bind(new InetSocketAddress(8080)); while (true) {//循环接收请求,分配子线程去执行请求 // 用于和客户端进行消息读写 SocketChannel socketChannel = channel.accept(); handle(socketChannel); } } public void handle(final SocketChannel socketChannel) throws IOException { // 2.通信 Thread thread = new Thread(new Runnable() { @Override public void run() { ByteBuffer buffer = ByteBuffer.allocate(8192); while (true) { try { buffer.clear(); socketChannel.read(buffer); // 从buffer 当中读出来 buffer.flip(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); String message = new String(bytes); System.out.println(message); // 写回去 buffer.rewind(); socketChannel.write(buffer); if (message.trim().equals("exit")) { break; } } catch (Exception e) { e.printStackTrace(); } } try { socketChannel.close(); } catch (IOException e) { e.printStackTrace(); } } }); thread.start(); } 

 

Se puede probar con el comando TCP service telnet 127.0.0.1 8080

Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/yuandengta/article/details/109183903
Recomendado
Clasificación