[Programación de red de sockets avanzada y práctica] [Notas] Explicación detallada de la optimización de la transmisión del servidor

Prefacio

Ya regresé a la escuela, pero aún no comencé la clase, por lo que estudiaré el curso [Programación avanzada y práctica de combate en red de Socket] https://coding.imooc.com/class/286.html que se puso en mantener durante las vacaciones de verano . Esta tarde, después de leer el Capítulo 7, me sentí un poco incómodo, me mordí la cabeza y seguí al profesor para teclear el código, el proceso de teclear el código fue bastante oscuro. Después de escribir el Capítulo 7, pasé mucho tiempo por la noche para comprender el código del Capítulo 7.

Siento que entiendo del 70% al 80%, la arquitectura y el empaque específicos probablemente se entienden, y todavía hay algunos detalles del código que no se han entendido en su lugar.

Antes de analizar lo siguiente, debe comprender la relación entre Selector y Channel. Puede consultar: https://www.jianshu.com/p/10717976c67c

1. Introducción de clases clave

IoArgs : una encapsulación simple de las operaciones ByteBuffer y define la interfaz de devolución de llamada al inicio y al inicio de la lectura y escritura.

IoSelctorProvider : una instancia global (una instancia de la clase de implementación) se mantiene en la demostración, y esta instancia contiene el selector global (consulte la figura siguiente).

Hay dos responsabilidades principales:

(1) Registre el SocketChannel en el Selector global y mantenga la supervisión del canal en poder del Selector (el canal registrado con el Selector).

(2) Inicie otro hilo para sondear todos los canales retenidos por Selctor (canales registrados con Selector). Cuando el canal se puede leer o escribir, la función de devolución de llamada correspondiente (Runnable) se obtiene del CallbackMap global a través de SelectionKey, y es ejecutada por el grupo de subprocesos.

SocketChannelAdapter : tiene la función de enviar y recibir mensajes de forma asíncrona, y define una devolución de llamada cuando el canal es legible o escribible, en el que interactúa con el objeto IoArgs, y el IoArgs procesado se vuelve a llamar al conector externo.

 

cantidad. . . Con solo mirar el texto, todavía se siente muy abstracto y pálido. . . Pero me he esforzado mucho en generalizar. . .

2. Diagrama de la arquitectura de demostración y análisis del proceso principal

Las imágenes son más casuales y algunas no son fáciles de expresar.

Solo hay un ServerSocket, lo compararé con el "servidor" por el momento. En TCPServer, el evento ACCEPT de ServerSockerChannel se monitorea a través de un Selector. Cuando hay un cliente para conectarse, obtenga el SocketChannel correspondiente al cliente (similar a "cliente"). Y compile ClientHandler y coloque el ClientHandler correspondiente en la lista global.


El significado literal de ClientHandler es más fácil de entender: el procesador del cliente. Hay tantos ClientHandlers como conexiones de cliente. Es el único responsable del manejo de las operaciones de lectura y escritura de su correspondiente cliente. Su constructor contiene la operación de configuración del Connector, por lo que el registro y el monitoreo del cliente se inician cuando se construye el objeto.


Veamos nuevamente IoSelectorProvider. Al final del Capítulo 7 del profesor, la Escritura relacionada en esta clase aún no está completa, lo siguiente solo discute la Lectura relacionada para comprender esta clase. Lo primero que vale la pena enfatizar es que IoSelectorProvider tiene solo 1 instancia en el global.

Esta instancia contiene el ReadSelector global, y ReadSelector es responsable de todos los canales que contiene (todos los canales registrados con ReadSelector) para leer eventos.

También hay un inputCallbackMap global en este ejemplo. Este también es un papel clave. Sabemos que la relación entre el ReadSelector global y cada SocketChannel (la relación generada después del registro) se puede identificar mediante la SelectionKey correspondiente. Cuando un SocketChannel es legible, se debe ejecutar la devolución de llamada correspondiente (HandleInputCallback). Por lo tanto, cuando se registra SocketChannel, las devoluciones de llamada activadas cuando cada SocketChannel es legible se almacenan en el mapa.

Cuando se puede leer un SocketChannel, se debe ejecutar la devolución de llamada correspondiente (HandleInputCallback). Esta devolución de llamada se entrega al grupo de subprocesos global inputHandlePool para una ejecución unificada. Este HandleInputCallback es el principal responsable de leer datos de SocketChannel a IoArgs y volver a llamar a los IoArgs de los datos cargados al conector externo.

3. Análisis de procesos combinado con código

Arriba, combinado con el diagrama de la arquitectura rudimentaria, se describen las clases clave de Demo, y en general se comprende el papel de cada clase y el proceso de ejecución principal. El siguiente es un análisis de todo el proceso en combinación con el código. Solo cuando comprenda completamente el código podrá depurar y realizar cambios secundarios.

Aquí solo se analiza el código modificado en el Capítulo 7.

No hay duda de que la clase de entrada del servidor es Servidor. La función del código en la captura de pantalla anterior es crear una nueva instancia global de IoSelectorProvider y ponerla en el contexto global IoContext.

 

La operación ReadAndPrint se elimina de la línea horizontal superior en el TCPServer, porque las responsabilidades relacionadas se entregan al ClientHandler, que es el único responsable de procesar las operaciones de lectura y escritura de su cliente correspondiente. Su constructor contiene la operación de configuración del conector, por lo que el registro y la supervisión del cliente (SocketChannel) se inicia cuando se construye el objeto.

 

El constructor de ClientHandler también se menciona anteriormente, principalmente para construir Connector y configurarlo.

 

Al ver esto, sabemos: ¡ tantos clientes como hay, hay tantos ClientHandlers como conectores y SocketChannelAdapters! ! ! Concéntrese en el método readNextMessage aquí . El método readNextMessage se ejecuta en la interfaz de devolución de llamada echoReceiveListener  (como se muestra en la figura siguiente). ¿por qué? Esto debe rastrearse hasta IoSelectorProvider.

 

Piense en el problema de la línea horizontal. La respuesta se muestra a continuación:

Cuando se crea el IoSelectorProvider global (en el constructor), se ejecuta el método startRead. En este método, se habilita otro subproceso separado (de alta prioridad) para sondear todos los canales en el ReadSelector y escuchar eventos legibles. También se menciona la descripción anterior. Cuando hay un canal legible, el correspondiente HandleInputCallback se obtiene a través de SelectionKey y es ejecutado por el grupo de subprocesos global inputHandlePool. Luego, durante la ejecución de la devolución de llamada HandleInputCallback, no necesitamos ni necesitamos monitorear el SocketChannel. Debido a que lo que hace HandleInputCallback es leer datos del canal a IoArgs, y el SocketChannel se está leyendo, ¿es necesario monitorear si es legible? ? Por tanto, en el método handleSelection, cancelamos temporalmente la monitorización del canal, lo que mejorará la eficacia de todo el sondeo.

Si no cancela el monitoreo aquí, causará un error. El grupo de subprocesos está ocupado, lo que hace que los eventos legibles del canal (cuando llega el mensaje) se procesen de manera intempestiva, lo que conduce
al procesamiento repetido de los eventos legibles del canal que se están procesando pero no se completan cuando se consulta el canal (seleccionar), y causa malignidad Bucle, lo que hace que el grupo de subprocesos esté más ocupado.

Entonces, ¿cuándo se reanudará el monitoreo de SocketChannel?

Luego tenemos que rastrear una serie de devoluciones de llamada.

HandleInputCallback lee datos de SocketChannel a IoArgs y vuelve a llamar a IoArgs de los datos cargados al conector externo. ¡El conector imprime los datos y vuelve a llamar a readNextMessage ! ! ! Rastreando este método, sabemos que finalmente en el método regietrSelection en IoSelectorProvider, se restaura la supervisión. (Vea abajo).

Bueno, mi comprensión de todo el código se ha expresado lo mejor que he podido. Hay algunos detalles del código (como: varios bloqueos, etc.), todavía no lo he descubierto. . . . Si hay algún error, corrígeme.

Supongo que te gusta

Origin blog.csdn.net/qq_43290318/article/details/108395386
Recomendado
Clasificación