Los tres componentes principales de NIO y ByteBuffer

Tabla de contenido

1. Tres componentes de NIO

1 canal

2, tampón

3, Selector

Dos, ByteBuffer

1. Uso básico

2. Estructura interna

3. Métodos comunes

método de asignación

método de lectura

Convertir entre cadena y ByteBuffer

Lecturas de dispersión

4. Lea el problema de la bolsa, la mitad de la bolsa

3. Programación de archivos

1, canal de archivo

2. Dos canales transmiten datos

3、Ruta

4, archivos


1. Tres componentes de NIO

E/S sin bloqueo E/S sin bloqueo

1 canal

El canal es el canal, aquí se refiere al canal bidireccional de datos, los datos se pueden leer desde el canal al búfer, o los datos del búfer se pueden escribir en el canal, y el flujo anterior es entrada o salida, y el canal es más bajo que la corriente

Los canales comunes son:

  • FileChannel: canal de transmisión de datos para archivos
  • DatagramChannel: canal de datos de transmisión UDP
  • SocketChannel: Es un canal de transmisión de datos cuando se hace TCP (se puede usar tanto cliente como servidor)
  • ServerSocketChannel: Es el canal de transmisión de datos cuando se hace TCP (servidor dedicado)

2, tampón

El búfer se utiliza para almacenar datos de lectura y escritura en el búfer. Los búfer comunes son:

ByteBuffer (almacenamiento en caché de datos en bytes) es una clase abstracta, y las clases de implementación son:

  • MapperByteBuffer
  • DirectByteBuffer
  • HeapByteBuffer

3, Selector

Un selector significa literalmente un selector y debe combinarse con la evolución del diseño del servidor para comprender su propósito.

El servidor maneja la comunicación de varios clientes. Cada vez que llega uno, se crea un subproceso para que el cliente proporcione servicios para el cliente. Si hay varios subprocesos, se abren varios subprocesos y cada subproceso administra una conexión. Cuando hay muchos conexiones, el No, porque los subprocesos ocuparán memoria, y cada subproceso ocupará memoria. Cuando haya 1.000 subprocesos, será demasiado grande y la memoria no podrá contenerlo. Sin embargo, la cantidad de núcleos de CPU es limitada, por lo que el costo del cambio de contexto de subprocesos es alto, lo que solo es adecuado para escenarios con una pequeña cantidad de conexiones .

Mejore el grupo de subprocesos para limitar la cantidad de subprocesos, pero esto hará que el socket funcione en modo de bloqueo, porque un subproceso tiene que administrar múltiples conexiones de socket, solo se puede procesar uno a la vez y el resto se bloqueará (el subproceso solo puede procesar un socket a la vez, no puede salir hasta que se desconecte el socket, incluso si el socket no tiene solicitudes de lectura o escritura, tiene que esperar), por lo que solo es adecuado para escenarios de conexión cortos .

Dos, ByteBuffer

1. Uso básico

Inicialice un búfer con un tamaño de 10 bytes, y luego lea, escriba y lea en un bucle. Un canal es un canal para leer datos. Los datos leídos cada vez se almacenan en el búfer, y luego la API en el búfer es llamado para obtener los datos.

Postura de uso correcta de ByteBuffer:

  1. Escribir datos en el búfer, como llamar a channel.read(buffer)
  2. Llame a flip() para cambiar al modo de lectura
  3. Lea datos del búfer, por ejemplo, llame a buffer.get()
  4. Llame a clear() o compact() para cambiar al modo de escritura
  5. Repita los pasos 1-4

2. Estructura interna

ByteBuffer tiene las siguientes propiedades importantes

  • capacidad de capacidad
  • puntero de lectura y escritura de posición , subíndice de índice
  • limitar las restricciones de lectura y escritura, cuántos bytes se deben leer y cuántos bytes se deben escribir

En el modo de escritura, la posición es la posición de escritura y el límite es igual a la capacidad. La siguiente figura muestra el estado después de escribir 4 bytes.

Después de que ocurre la acción de filtro , la posición cambia a la posición de lectura y los interruptores de límite al límite de lectura (la última posición escrita)

Después de leer 4 bytes, el estado

Después de que ocurre la acción clara , el estado cambia del modo de lectura al modo de escritura

El método compacto consiste en comprimir la parte que no se ha leído hacia adelante y luego cambiar al modo de escritura.

3. Métodos comunes

método de asignación

El método ByteBuffer.allocate() puede pasar parámetros para asignar memoria para ByteBuffer. Es fijo y no se puede ajustar dinámicamente. Si excede esta capacidad, se informará un error. Netty ha mejorado byteBuffer para permitir el ajuste dinámico.

El método allocate se usa para inicializar la memoria del montón de Java (la eficiencia de lectura y escritura es baja y se verá afectada por GC, y el marcado y la copia de GC pueden causar la copia de datos), y el método allocateDirect () se usa para inicializar usando direct Memoria (la eficiencia de lectura y escritura es alta y habrá una copia de datos menos; la eficiencia de la asignación de memoria es baja y el uso inadecuado puede causar fugas de memoria )

método de lectura

rebobinar (): los datos se pueden leer repetidamente. Originalmente, el puntero se mueve hacia atrás después de leer una vez en orden, pero el código fuente de rebobinado moverá directamente el puntero a 0 y volverá a leer. También hay métodos de marcado y restablecimiento que se usan junto con el rebobinado . La marca registrará la posición actual y el restablecimiento restablecerá la posición a la posición de la marca. Estos dos son mejoras para el rebobinado.

Convertir entre cadena y ByteBuffer

Cadena a ByteBuffer

El primero es convertirlo manualmente en forma binaria y ponerlo; el segundo es usar el método de codificación proporcionado por charset , que proporciona muchos formatos de codificación, y cambiará automáticamente al modo de lectura después de ponerlo ; el tercero es también el método warp proporcionado por nio.

ByteBuffer a cadena

Después de cambiar al modo de lectura, si es el búfer transferido desde el primer modo, primero debe agregar el método flip para cambiar el modo y luego convertirlo con el método de decodificación de charset.El resultado devuelto es un CharBuffer más toString para convertirlo en una cadena

Lecturas de dispersión

Los datos de lectura dispersos uno dos tres, usando el siguiente método para leer pueden llenar datos en múltiples búferes

4. Lea el problema de la bolsa, la mitad de la bolsa

Solución:

Escribimos un método para recibir mensajes, primero cambiamos al modo de lectura, luego recorremos el delimitador para interceptar la longitud del mensaje y luego almacenamos el mensaje en el byteBuffer (bucle desde el origen para leer hasta el destino para escribir).

3. Programación de archivos

1, canal de archivo

FileChannel solo puede funcionar en modo de bloqueo

Obtener

FileChannel no se puede abrir directamente, y FileChannel debe obtenerse a través de FileInputStream, FileOutputStream o RandomAccessFile, todos los cuales tienen el método getChannel

  • El canal obtenido a través de FileInputStream solo se puede leer
  • El canal obtenido a través de FileOutputStream solo se puede escribir
  • Si puede leer y escribir a través de RandomAccessFile depende del modo de lectura y escritura al construir RandomAccessFile

leer

Leerá los datos del canal y los llenará en ByteBuffer.El valor devuelto indica cuántos bytes se han leído y -1 indica que se ha llegado al final del archivo.

int readBytes = channel.read(buffer);

escribir

Llamar a channel.write in while se debe a que el método de escritura no puede garantizar que todo el contenido del búfer se escribirá en el canal al mismo tiempo, por lo que es necesario realizar un bucle para determinar si hay alguno. 

cierre

El canal debe estar cerrado, pero llamar al método de cierre de FileInputStream también llamará indirectamente al método de cierre del canal.

escribir a la fuerza

Por consideraciones de rendimiento, el sistema operativo almacenará en caché los datos, y cuando se cierre el canal final, los datos se sincronizarán con el disco. En lugar de escribir en el disco inmediatamente, puede llamar al método force(true) para escribir el archivo . contenido y metadatos al disco inmediatamente.

2. Dos canales transmiten datos

El método transferTo es transferir los datos de un canal a otro canal. El primer parámetro es la posición de inicio, el segundo parámetro es el tamaño de los datos transferidos y el tercer parámetro es la posición de destino.

La eficiencia de este método será mayor que la del flujo de salida para escribir (optimizado por copia cero en la parte inferior del sistema operativo)

El tamaño de los datos transmitidos está limitado a 2 g, por lo que es posible que no podamos transferirlos todos a la vez, por lo que debemos mejorarlo:

 De esta forma, los datos de más de 2 g se pueden transmitir varias veces.

3、Ruta

jdk7 introdujo las clases Path y Paths

  • La ruta se utiliza para representar la ruta del archivo.
  • Paths es una clase de herramienta utilizada para obtener instancias de Path

  •   .representa la ruta actual
  •  .. representa la ruta del nivel superior

4, archivos

También es una clase nueva en 1.7, verifique si el archivo existe

 

 

Supongo que te gusta

Origin blog.csdn.net/weixin_54232666/article/details/131464665
Recomendado
Clasificación