Proyecto de combate C++ - aplicación práctica

Tabla de contenido

Dos fases de E/S típica (E/S de red)

Cinco modelos IO en Linux

1. bloqueo bloqueo

2. Sin bloqueo

3. Multiplexación IO

4. Unidad de señal

5. Asíncrono

Servidor web

 Protocolo HTTP (protocolo de capa de aplicación)

Introducción

descripción general

principio de funcionamiento

Formato de mensaje de solicitud HTTP

Formato de mensaje de respuesta HTTP 

Método de solicitud HTTP 

Código de estado HTTP

Framework básico de programación de servidores 

 Dos modos eficientes de manejo de eventos

modo reactor

modo proactor 

Simular modo Proactor 

Grupo de subprocesos 

Máquina de estados finitos 

Evento EPOLLONESHOT

Prueba de estrés del servidor


Dos fases de E/S típica (E/S de red)

I y O representan entrada y salida, respectivamente. La comunicación de red se realiza a través del socket de red, que en realidad es un búfer en el núcleo.

Network IO se divide en dos etapas: preparación de datos, lectura y escritura de datos (estos dos conceptos son diferentes y no se pueden confundir)

Preparación de datos: de acuerdo con el estado listo de la operación IO del sistema

        Dividido en: bloqueo, no bloqueo

Lectura y escritura de datos: según el modo de interacción entre el kernel y la aplicación

        Dividido en: síncrono, asíncrono

Cuando se trata de IO, tanto el bloqueo como el no bloqueo son síncronos, y solo llamar a una API especial es asíncrono

Resumir:

        Una E/S de red clásica se divide en dos etapas: preparación de datos, lectura y escritura de datos. Los datos listos se dividen en bloqueo y no bloqueo. Bloquear es llamar al método IO y el hilo entra en estado de bloqueo (cuando no llega el dato no regresa, se bloquea y espera a que llegue el dato), y no bloqueo (no llega el dato y regresa , juzgado por el valor devuelto) no cambiará el estado del subproceso, a través del juez de valor devuelto. Independientemente de si es leído o recibido, si el valor de retorno es -1, se juzgará según el estado de retorno que no hay datos en el búfer y si es interrumpido suavemente por una señal y si se vuelve a llamar.

        La lectura y escritura de datos se dividen en síncrona y asíncrona. Sabemos que el socket es un búfer en el kernel. Sincronización significa que la aplicación lee datos del kernel. En este momento, el contenido del trabajo de la aplicación es leer datos del kernel. núcleo Otras cosas. Y la asincronía es permitir que el kernel nos ayude a completar la operación de lectura y escritura de datos. Cuando se completa la lectura y escritura de datos, se notifica a la aplicación a través de un método de notificación. Los datos escritos son suficientes. Generalmente, necesitamos pasar el archivo descriptor (socket), buf (contenedor para almacenar datos) y método de notificación (señal sigio). Asíncronamente a través de llamadas API especiales, aio_read aio_write

        El método síncrono es menos eficiente que el método asíncrono y el método asíncrono es más complicado de implementar.

Cinco modelos IO en Linux

1. bloqueo bloqueo

La persona que llama llama a una función, espera a que regrese la función, no hace nada durante el período y continúa verificando si la función ha regresado, y debe esperar a que regrese la función antes de continuar con el siguiente paso.

Un subproceso (o proceso) en un estado bloqueado no consume CPU, pero el subproceso (proceso) no puede hacer otras cosas 

2. Sin bloqueo

Espera sin bloqueo, verifique si el evento IO está listo de vez en cuando. Hacer otras cosas sin estar preparado. La llamada al sistema de ejecución de E/S sin bloqueo siempre regresa inmediatamente, sin importar si el evento ha ocurrido o no, si el evento no ha ocurrido, devolverá -1.En este momento, los dos casos se pueden distinguir según errno Para aceptar, recibir y enviar, el evento no ha ocurrido errno generalmente se establece en EAGAIN.

Generalmente, se usa el método de sondeo while.Cuando no llegan datos al búfer, se pueden hacer otras cosas. Comparar el consumo de recursos del sistema. El no bloqueo se puede configurar mediante fcntl. Por ejemplo: hay 10000 clientes para enviar datos, cada ciclo tendrá 10000 llamadas al sistema. 

3. Multiplexación IO

Linux usa las funciones select/poll/epoll para implementar el modelo de multiplexación de E/S. Estas funciones también bloquearán el proceso, pero la diferencia con el bloqueo de E/S es que estas funciones pueden bloquear varias operaciones de E/S al mismo tiempo. Además, las funciones IO de múltiples operaciones de lectura y operaciones de escritura se pueden detectar al mismo tiempo. La función de operación de E/S no se llama realmente hasta que haya datos que se puedan leer o escribir.

Se pueden detectar múltiples IO al mismo tiempo, y el trabajo de monitoreo generalmente se entrega al kernel.Cuando llegan los datos, la aplicación llama a lectura para leer y escribir datos. Puede entenderse como una mejora del sondeo ocupado y sin bloqueo. Se pueden detectar varios clientes simultáneamente en un hilo o proceso

4. Unidad de señal

Linux usa sockets para E/S controlada por señales, instala una función de procesamiento de señales, el proceso continúa ejecutándose sin bloqueos, cuando el evento de E/S está listo, el proceso recibe la señal SIGIO y luego procesa el evento de E/S.

Es procesado por la señal sigio. Cuando los datos estén listos, envíe la señal, luego capture la señal y llame a leer para leer y escribir datos.

El kernel es asíncrono en la primera etapa y síncrono en la segunda etapa; la diferencia con el IO sin bloqueo es que proporciona un mecanismo de notificación de mensajes, que no requiere un sondeo y verificación continuos por parte de los procesos del usuario, reduce la cantidad de API del sistema llamadas y mejora la eficiencia.

5. Asíncrono

En Linux, puede llamar a la función aio_read para indicar la descripción del kernel, el puntero del búfer de palabras y el tamaño del búfer, el desplazamiento del archivo y el método de notificación, y luego regresar inmediatamente y notificar a la aplicación después de que el kernel copie los datos en el búfer.

 El kernel completa las operaciones de monitoreo y lectura y escritura, y cuando se completa la lectura y escritura de datos, notifica al programa de aplicación que procese los datos.

/* Asynchronous I/O control block. */
struct aiocb
{
int aio_fildes; /* File desriptor. */
int aio_lio_opcode; /* Operation to be performed. */
int aio_reqprio; /* Request priority offset. */
volatile void *aio_buf; /* Location of buffer. */
size_t aio_nbytes; /* Length of transfer. */
struct sigevent aio_sigevent; /* Signal number and value. */
/* Internal members. */
struct aiocb *__next_prio;
int __abs_prio;
int __policy;
int __error_code;
__ssize_t __return_value;
#ifndef __USE_FILE_OFFSET64
__off_t aio_offset; /* File offset. */
char __pad[sizeof (__off64_t) - sizeof (__off_t)];
#else
__off64_t aio_offset; /* File offset. */
#endif
char __glibc_reserved[32];
};

Servidor web

Un servidor web es un software de servidor (programa) o el hardware (computadora) que ejecuta el software de servidor. Su función principal es comunicarse con el cliente (generalmente un navegador (Browser)) a través del protocolo HTTP para recibir, almacenar y procesar la solicitud HTTP del cliente, y hacer una respuesta HTTP a la solicitud y devolver la solicitud al cliente Contenido (archivo, página web, etc.) o devolver un mensaje de error.

 

 Protocolo HTTP (protocolo de capa de aplicación)

Explicación del desarrollo de GoWeb

Introducción

El Protocolo de transferencia de hipertexto (HTTP) es un protocolo simple de solicitud y respuesta que generalmente se ejecuta sobre TCP. Especifica qué tipo de mensajes puede enviar el cliente al servidor y qué tipo de respuestas puede obtener. Los encabezados de los mensajes de solicitud y respuesta se dan en ASCII, mientras que el contenido del mensaje tiene un formato similar a MIME. HTTP es la base de la comunicación de datos para la World Wide Web. El desarrollo de HTTP fue iniciado por Tim Berners-Lee en el CERN en 1989. El desarrollo estándar de HTTP está coordinado por el World Wide Web Consortium (W3C) y el Internet Engineering Task Force (IETF), y finalmente lanzó una serie de RFC, el más famoso de los cuales se publicó en junio de 1999 RFC 2616, define una versión del protocolo HTTP que se usa ampliamente en la actualidad: HTTP 1.1.

descripción general

HTTP es un estándar (TCP) para solicitudes y respuestas del lado del cliente (usuario) y del lado del servidor (sitio web). Mediante el uso de un navegador web, rastreador web u otras herramientas, el cliente inicia una solicitud HTTP al puerto especificado en el servidor (el puerto predeterminado es 80). Llamamos a este cliente un agente de usuario. Algunos recursos, como archivos HTML e imágenes, se almacenan en el servidor de respuesta. Llamamos a este servidor de respuesta el servidor de origen. Puede haber varias "capas intermedias" entre el agente de usuario y el servidor de origen, como servidores proxy, puertas de enlace o túneles. Aunque el protocolo TCP/IP es la aplicación más popular en Internet, en el protocolo HTTP no hay ningún requisito para usarlo ni las capas que admite. De hecho, HTTP se puede implementar en cualquier protocolo de Internet u otra red. HTTP asume que sus protocolos subyacentes proporcionan un transporte confiable . Por lo tanto, puede utilizar cualquier protocolo que pueda proporcionar tales garantías. Por lo tanto, utiliza TCP como su capa de transporte en la familia de protocolos TCP/IP. Por lo general, el cliente HTTP inicia una solicitud para crear una conexión TCP al puerto especificado del servidor (puerto 80 de forma predeterminada). El servidor HTTP escucha las solicitudes de los clientes en ese puerto. Una vez que se recibe la solicitud, el servidor devolverá un estado al cliente, como "HTTP/1.1 200 OK", y el contenido devuelto, como el archivo solicitado, el mensaje de error u otra información.

principio de funcionamiento

El protocolo HTTP define cómo un cliente web solicita una página web de un servidor web y cómo el servidor transmite una página web al cliente. El protocolo HTTP emplea un modelo de solicitud/respuesta. El cliente envía un mensaje de solicitud al servidor y el mensaje de solicitud incluye el método de solicitud, la URL, la versión del protocolo, el encabezado de la solicitud y los datos de la solicitud. El servidor responde con una línea de estado que incluye la versión del protocolo, el código de éxito o error, la información del servidor, los encabezados de respuesta y los datos de respuesta.

Los siguientes son los pasos de una solicitud/respuesta HTTP: 1. El cliente se conecta al servidor web Un cliente HTTP, generalmente un navegador, establece una conexión de socket TCP con el puerto HTTP del servidor web (80 por defecto). Por ejemplo, http://www.baidu.com. (URL) 2. Envíe una solicitud HTTP a través del socket TCP y el cliente enviará un mensaje de solicitud de texto al servidor web. Un mensaje de solicitud consta de cuatro partes: línea de solicitud, encabezado de solicitud, línea en blanco y datos de solicitud. 3. El servidor acepta la solicitud y devuelve una respuesta HTTP. El servidor web analiza la solicitud y localiza el recurso solicitado. El servidor escribe una copia del recurso en un socket TCP, que el cliente lee. Una respuesta consta de 4 partes: línea de estado, encabezado de respuesta, línea en blanco y datos de respuesta. 4. Liberar la conexión Conexión TCP Si el modo de conexión está cerrado, el servidor cerrará activamente la conexión TCP, y el cliente cerrará la conexión pasivamente y liberará la conexión TCP, si el modo de conexión está activo, la conexión se mantendrá durante un período de tiempo, durante el cual puede continuar recibiendo solicitudes 5. El navegador del cliente analiza el contenido HTML El navegador del cliente primero analiza la línea de estado, buscando un código de estado que indique si la solicitud fue exitosa. A continuación, se analiza cada encabezado de respuesta, lo que indica el siguiente documento HTML en bytes y el conjunto de caracteres del documento. El navegador del cliente lee el HTML de datos de respuesta, lo formatea de acuerdo con la sintaxis de HTML y lo muestra en la ventana del navegador.

Formato de mensaje de solicitud HTTP

 

Formato de mensaje de respuesta HTTP 

 

Método de solicitud HTTP 

El protocolo HTTP/1.1 define ocho métodos (también llamados "acciones") para manipular recursos específicos de diferentes maneras: 1. GET: envía una solicitud de "visualización" al recurso especificado. El uso del método GET solo debe usarse para leer datos y no debe usarse para operaciones de "efecto secundario", como en una aplicación web. Una de las razones de esto es que las arañas web y similares pueden acceder aleatoriamente a GET. 2. HEAD: Al igual que el método GET, envía una solicitud de un recurso específico al servidor. Es solo que el servidor no devolverá la parte de texto del recurso. Su ventaja es que mediante este método se puede obtener "información sobre el recurso" (metainformación o metadatos) sin tener que transmitir todo el contenido. 3. POST: envíe datos al recurso especificado y solicite el procesamiento del servidor (como enviar un formulario o cargar un archivo). Los datos se incluyen en el cuerpo de la solicitud. Esta solicitud puede crear un nuevo recurso o modificar un recurso existente, o ambos. 4. PUT: carga el contenido más reciente en la ubicación de recursos especificada. 5. ELIMINAR: solicite al servidor que elimine el recurso identificado por la URI de solicitud. 6. TRACE: Hacer eco de la solicitud recibida por el servidor, principalmente para pruebas o diagnóstico. 7. OPCIONES: este método permite que el servidor devuelva todos los métodos de solicitud HTTP admitidos por el recurso. Use '*' para reemplazar el nombre del recurso y envíe una solicitud de OPCIONES al servidor web para probar si el servidor funciona normalmente. 8. CONECTAR: Reservado en el protocolo HTTP/1.1 para un servidor proxy que puede cambiar la conexión a una canalización. Normalmente se utiliza para conexiones a servidores con cifrado SSL (a través de servidores proxy HTTP no cifrados).

Código de estado HTTP

La primera línea de todas las respuestas HTTP es la línea de estado, seguida del número de versión HTTP actual, un código de estado de 3 dígitos y una frase que describe el estado, separados por espacios.

El primer dígito del código de estado representa el tipo de respuesta actual:

Mensaje 1xx: el servidor ha recibido la solicitud, continúe procesando

2xx éxito: el servidor ha recibido, entendido y aceptado correctamente la solicitud

Redirección 3xx: se requiere una acción posterior para completar esta solicitud

Error de solicitud 4xx: la solicitud contiene un error léxico o no se puede ejecutar

Error del servidor 5xx: el servidor encontró un error al procesar una solicitud correcta

Aunque RFC 2616 ha recomendado frases para describir el estado, como "200 OK" y "404 Not Found", los desarrolladores WEB aún pueden decidir qué frases usar para mostrar descripciones de estado localizadas o información personalizada.

Framework básico de programación de servidores 

Aunque hay muchos tipos de programas de servidor, su marco básico es el mismo, la diferencia radica en el procesamiento lógico.

La unidad de procesamiento de E/S es el módulo en el que el servidor gestiona las conexiones de los clientes. Por lo general, completa las siguientes tareas: esperar y aceptar nuevas conexiones de clientes, recibir datos de clientes y devolver datos de respuesta del servidor al cliente. Sin embargo, el envío y la recepción de datos no se realizan necesariamente en la unidad de procesamiento de E/S, sino que también se pueden realizar en la unidad lógica, y la ubicación de ejecución específica depende del modo de procesamiento de eventos. Una unidad lógica suele ser un proceso o subproceso. Analiza y procesa los datos del cliente y luego pasa los resultados a la unidad de procesamiento de E/S o directamente al cliente (según el modo de procesamiento de eventos). Un servidor suele tener varias unidades lógicas para implementar el procesamiento simultáneo de varias tareas de clientes. Las unidades de almacenamiento en red pueden ser bases de datos, cachés y archivos, pero no son obligatorias. Una cola de solicitudes es una abstracción de cómo se comunican las unidades. Cuando una unidad de procesamiento de E/S recibe una solicitud de cliente, debe notificar de alguna manera a una unidad lógica para que procese la solicitud. De manera similar, cuando varias unidades lógicas acceden a una unidad de almacenamiento al mismo tiempo, también se requiere algún mecanismo para coordinar y manejar las condiciones de carrera. Las colas de solicitudes generalmente se implementan como parte de un grupo. 

 Dos modos eficientes de manejo de eventos

Los programas de servidor generalmente necesitan manejar tres tipos de eventos: eventos de E/S, señales y eventos de temporización . Hay dos modos de procesamiento de eventos eficientes: Reactor y Proactor El modelo de E/S síncrona se usa generalmente para implementar el modo Reactor, y el modelo de E/S asíncrona se usa generalmente para implementar el modo Proactor.

modo reactor

El subproceso principal (unidad de procesamiento de E/S) solo se requiere para monitorear si ocurre un evento en el descriptor de archivo y, de ser así, notificar inmediatamente al subproceso de trabajo (unidad lógica) del evento y colocar el evento de lectura y escritura del socket en la cola de solicitudes. Entregado al subproceso de trabajo para su procesamiento. Aparte de eso, el hilo principal no hace ningún otro trabajo sustancial. La lectura y escritura de datos, la aceptación de nuevas conexiones y el manejo de solicitudes de clientes se realizan en subprocesos de trabajo.

El flujo de trabajo del modo Reactor implementado usando E/S síncrona (tomando epoll_wait como ejemplo) es:

1. El subproceso principal registra el evento de lectura lista en el socket en la tabla de eventos del kernel epoll.

2. El subproceso principal llama a epoll_wait para esperar a que se lean los datos en el socket.

3. Cuando hay datos legibles en el socket, epoll_wait notifica al subproceso principal. El subproceso principal coloca eventos legibles de socket en la cola de solicitudes.

4. Se despierta un subproceso de trabajo inactivo en la cola de solicitudes, lee los datos del socket, procesa la solicitud del cliente y luego registra el evento de escritura lista en el socket en la tabla de eventos del kernel epoll.

5. Cuando el subproceso principal llama a epoll_wait, espera a que se pueda escribir en el socket.

6. Cuando se puede escribir en el socket, epoll_wait notifica al subproceso principal. El subproceso principal coloca eventos de socket grabables en la cola de solicitudes.

7. Se despierta un subproceso de trabajo inactivo en la cola de solicitudes y escribe el resultado del servidor que procesa la solicitud del cliente en el socket. El flujo de trabajo del modo Reactor:

modo proactor 

En el modo Proactor, todas las operaciones de E/S se transfieren al subproceso principal y al kernel para su procesamiento (para lectura y escritura), y el subproceso de trabajo solo es responsable de la lógica empresarial.

El flujo de trabajo del modo Proactor implementado usando el modelo de E/S asíncrono (tome aio_read y aio_write como ejemplos) es:

1. El subproceso principal llama a la función aio_read para registrar el evento de finalización de lectura en el socket con el kernel, y le dice al kernel la ubicación del búfer de lectura del usuario y cómo notificar a la aplicación cuando se completa la operación de lectura (aquí, tome una señal como ejemplo).

2. El subproceso principal continúa procesando otra lógica.

3. Cuando los datos del socket se leen en el búfer del usuario, el kernel enviará una señal a la aplicación para notificarle que los datos están disponibles.

4. La función de procesamiento de señales predefinida del programa de aplicación selecciona un subproceso de trabajo para procesar la solicitud del cliente. Una vez que el subproceso de trabajo termina de procesar la solicitud del cliente, llama a la función aio_write para registrar el evento de finalización de escritura en el socket con el kernel, y le dice al kernel la posición del búfer de escritura del usuario y cómo notificar a la aplicación cuando la operación de escritura esta completado.

5. El subproceso principal continúa procesando otra lógica.

6. Después de que los datos en el búfer del usuario se escriban en el socket, el núcleo enviará una señal a la aplicación para notificarle que se han enviado los datos.

7. La función de procesamiento de señal predefinida del programa de aplicación selecciona un subproceso de trabajo para realizar el procesamiento posterior, como decidir si se cierra el zócalo.

El flujo de trabajo del modo Proactor:

Simular modo Proactor 

Simule el modo Proactor usando E/S síncrona. El principio es: el subproceso principal realiza operaciones de lectura y escritura de datos, y después de que se completa la lectura y escritura, el subproceso principal notifica al subproceso de trabajo de este "evento de finalización". Luego, desde la perspectiva de los subprocesos de trabajo, obtienen directamente los resultados de la lectura y escritura de datos, y lo siguiente que deben hacer es procesar lógicamente los resultados de lectura y escritura.

El flujo de trabajo del modo Proactor simulado utilizando el modelo de E/S síncrona (tomando epoll_wait como ejemplo) es el siguiente:

1. El subproceso principal registra el evento de lectura lista en el socket en la tabla de eventos del kernel epoll.

2. El subproceso principal llama a epoll_wait para esperar a que se lean los datos en el socket.

3. Cuando hay datos legibles en el socket, epoll_wait notifica al subproceso principal. El subproceso principal realiza un bucle para leer datos del socket hasta que no haya más datos para leer, luego encapsula los datos leídos en un objeto de solicitud y los inserta en la cola de solicitudes.

4. Se despierta un subproceso de trabajo inactivo en la cola de solicitudes, obtiene el objeto de solicitud y procesa la solicitud del cliente, y luego registra el evento de escritura lista en el socket en la tabla de eventos del kernel epoll.

5. El subproceso principal llama a epoll_wait para esperar a que se pueda escribir en el socket.

6. Cuando se puede escribir en el socket, epoll_wait notifica al subproceso principal. El subproceso principal escribe el resultado del servidor que procesa la solicitud del cliente en el socket.

 

Grupo de subprocesos 

El grupo de subprocesos es un grupo de subprocesos creados previamente por el servidor, y la cantidad de subprocesos en el grupo de subprocesos debe ser similar a la cantidad de CPU. Todos los subprocesos secundarios en el grupo de subprocesos ejecutan el mismo código. Cuando llega una nueva tarea, el subproceso principal seleccionará un subproceso en el grupo de subprocesos para servirlo de alguna manera. En comparación con la creación dinámica de subprocesos, el costo de seleccionar un subproceso existente es obviamente mucho menor.

En cuanto a qué subproceso secundario elige el subproceso principal para realizar la nueva tarea, hay muchas maneras:

El subproceso principal utiliza algún algoritmo para seleccionar activamente subprocesos secundarios. Los algoritmos más simples y de uso más común son el algoritmo aleatorio y el algoritmo Round Robin (selección por turnos), pero los algoritmos mejores y más inteligentes distribuirán las tareas de manera más uniforme entre cada subproceso de trabajo, lo que reducirá la presión general sobre el servidor. El subproceso principal y todos los subprocesos secundarios se sincronizan a través de una cola de trabajo compartida en la que duermen los subprocesos secundarios. Cuando llega una nueva tarea, el subproceso principal agrega la tarea a la cola de trabajo. Esto despertará los subprocesos secundarios que están esperando la tarea, pero solo un subproceso secundario obtendrá la "toma de control" de la nueva tarea, puede tomar la tarea de la cola de trabajo y ejecutarla, mientras que los otros subprocesos secundarios continuarán. dormir en la cola de trabajo.

El modelo general de un grupo de subprocesos es:

El factor limitante más directo para la cantidad de subprocesos en el grupo de subprocesos es la cantidad N de procesadores (procesadores/núcleos) de la unidad central de procesamiento (CPU): si su CPU es de 4 núcleos, para tareas de uso intensivo de CPU (como edición de video Para tareas que consumen recursos informáticos de la CPU), es mejor establecer la cantidad de subprocesos en el grupo de subprocesos en 4 (o +1 para evitar el bloqueo de subprocesos causado por otros factores); La cantidad de núcleos, porque la competencia entre subprocesos no son los recursos informáticos de la CPU, sino IO, y el procesamiento de IO es generalmente lento. Los subprocesos con más núcleos lucharán por más tareas para la CPU, de modo que la CPU no estará inactiva durante el procesamiento del subproceso. proceso de IO conducen a la pérdida de recursos.

El espacio se intercambia por tiempo, desperdiciando recursos de hardware del servidor a cambio de eficiencia operativa. Un grupo es una colección de recursos que se crean e inicializan por completo cuando se inicia el servidor.Esto se denomina recurso estático. Cuando el servidor ingresa a la etapa de operación formal y comienza a procesar las solicitudes de los clientes, si necesita recursos relacionados, se pueden obtener directamente del grupo sin asignación dinámica. Cuando el servidor termina de procesar la conexión de un cliente, puede volver a colocar los recursos relacionados en el grupo, sin ejecutar llamadas al sistema para liberar recursos. 

Máquina de estados finitos 

Un método de programación eficiente dentro de la unidad lógica: máquina de estados finitos (finite state machine). Algunos encabezados de protocolo de capa de aplicación contienen campos de tipo de paquete de datos, y cada tipo se puede asignar a un estado de ejecución de una unidad lógica, y el servidor puede escribir la lógica de procesamiento correspondiente en función de él. La siguiente es una máquina de estados finitos independiente del estado:

STATE_MACHINE( Package _pack )
{
PackageType _type = _pack.GetType();
switch( _type )
{
case type_A:
process_package_A( _pack );
break;
case type_B:
process_package_B( _pack );
break;
}
}

Esta es una máquina de estados finitos simple, excepto que cada estado de la máquina de estados es independiente entre sí, es decir, no hay transición entre estados. La transición entre estados requiere la unidad interna de la máquina de estado, como se muestra en el siguiente código:

STATE_MACHINE()
{
State cur_State = type_A;

while( cur_State != type_C )
{
Package _pack = getNewPackage();
switch( cur_State )
{
case type_A:
process_package_state_A( _pack );
cur_State = type_B;
break;
case type_B:
process_package_state_B( _pack );
cur_State = type_C;
break;
}
}
}

La máquina de estado contiene tres estados: tipo_A, tipo_B y tipo_C, donde tipo_A es el estado inicial de la máquina de estado y tipo_C es el estado final de la máquina de estado. El estado actual de la máquina de estado se registra en la variable cur_State. Durante un ciclo, la máquina de estado primero obtiene un nuevo paquete de datos a través del método getNewPackage y luego juzga cómo procesar el paquete de datos de acuerdo con el valor de la variable cur_State. Una vez que se procesa el paquete de datos, la máquina de estado realiza la transición de estado pasando el valor del estado de destino a la variable cur_State. Luego, cuando la máquina de estado ingrese al siguiente ciclo, ejecutará la lógica correspondiente al nuevo estado.

Evento EPOLLONESHOT

Incluso si se puede usar el modo ET, un evento en un socket puede activarse varias veces. Esto puede causar un problema en los programas concurrentes. Por ejemplo, un subproceso comienza a procesar los datos después de leer los datos en un determinado socket, y durante el proceso de procesamiento de datos, hay nuevos datos para leer en el socket (EPOLLIN se activa nuevamente) y otro subproceso se activa. en este momento Lea estos nuevos datos. Entonces, hay una situación en la que dos subprocesos operan un socket al mismo tiempo. Una conexión de socket solo es procesada por un subproceso en cualquier momento, lo que se puede realizar mediante el uso del evento EPOLLONESHOT de epoll. Para el descriptor de archivo registrado con el evento EPOLLONESHOT, el sistema operativo activa como máximo un evento legible, escribible o anormal registrado en él, y solo se activa una vez, a menos que usemos la función epoll_ctl para restablecer el evento EPOLLONESHOT registrado en el descriptor de archivo. De esta forma, cuando un subproceso está procesando un determinado socket, es imposible que otros subprocesos tengan la oportunidad de operar el socket. Pero pensándolo al revés, una vez que un subproceso procesa el socket registrado con el evento EPOLLONESHOT, el subproceso debe restablecer inmediatamente el evento EPOLLONESHOT en el socket para garantizar que el evento EPOLLIN se pueda activar cuando el socket sea legible la próxima vez. Esto, a su vez, da a otros subprocesos de trabajo la oportunidad de continuar procesando el socket. 

Prueba de estrés del servidor

Webbench es una herramienta de prueba de estrés de rendimiento web muy conocida y excelente en Linux. Está desarrollado por Lionbridge Corporation. Pruebe el rendimiento de diferentes servicios en el mismo hardware y el funcionamiento del mismo servicio en hardware diferente. Muestra dos cosas sobre el servidor: el número de solicitudes de respuesta por segundo y la cantidad de datos transmitidos por segundo.

Principio básico: Webbench primero bifurca múltiples subprocesos, y cada subproceso realiza pruebas de acceso web en un ciclo. El proceso hijo le dice al proceso padre el resultado del acceso a través de la canalización, y el proceso padre hace las estadísticas finales.

demostración de prueba:

 

Supongo que te gusta

Origin blog.csdn.net/weixin_46120107/article/details/126641472
Recomendado
Clasificación