Presentamos EXtensible Server Core (exsc). Parte 1

imagen



¡Hola a todos! Quiero compartir con el público el marco en base al cual actualmente hay muchos servidores que atienden a miles de clientes en varios sistemas de servidores. exsc (EXtensible Server Core) es un marco escrito en C y le permite tener uno o más subprocesos de servidor dentro de una aplicación. Cada subproceso del servidor es capaz de servir a una gran cantidad de clientes. Aunque el marco se puede utilizar en un modelo de solicitud-respuesta, fue diseñado principalmente para mantener una conexión constante con una gran cantidad de clientes e intercambiar mensajes en tiempo real. Como a mí mismo me gusta tomar un proyecto HelloWorld listo para usar, compilarlo y ver cómo funciona todo, al final del artículo publicaré un enlace a dicho proyecto.



Muchas operaciones se realizan para una conexión específica. En el marco de este marco, la estructura exsc_excon es responsable de la conexión. Esta estructura tiene los siguientes campos:



ix - índice de conexión. Este es el número de serie de la conexión que estaba libre en el momento en que el cliente se conectó.

id : identificador de conexión. Este es un número de conexión único. A diferencia de un índice, no se repite.

addr -

nombre de la dirección IP del cliente - nombre de la conexión. Se pueden nombrar varias conexiones con el mismo nombre y luego se puede enviar algún mensaje a todas las conexiones con el mismo nombre (consulte la función exsc_sendbyname).



Inicialización del kernel



Para trabajar con el kernel, necesitamos inicializarlo usando la función



void exsc_init(int maxsrvcnt);
      
      





El parámetro maxsrvcnt le dice al kernel cuántos subprocesos del servidor usaremos dentro de nuestra aplicación.



Inicio de la secuencia del servidor



A continuación, debemos iniciar la secuencia del servidor utilizando la función



int exsc_start(uint16_t port, int timeout, int timeframe, int recvbufsize, int concnt,
               void newcon(struct exsc_excon excon),
               void closecon(struct exsc_excon excon),
               void recv(struct exsc_excon excon, char *buf, int bufsize),
               void ext());
      
      





puerto : el puerto que escuchará la transmisión del servidor.



tiempo de espera : indica cuánto tiempo esperará el hilo del servidor por cualquier actividad del cliente. Si durante este tiempo el cliente no ha enviado ningún mensaje, el hilo del servidor cierra dicha conexión. Por lo tanto, si queremos mantener una conexión constante y configurar este parámetro por ejemplo 30 segundos, entonces es necesario enviar cualquier mensaje de ping cada 10-15 segundos.



periodo de tiempo- el período de tiempo durante el cual permitimos que se ejecute la solicitud. Por ejemplo, si este valor se establece en 100 milisegundos y el hilo del servidor ha procesado todas las solicitudes actuales de los usuarios en 10 segundos, dejará los 90 milisegundos restantes al procesador para realizar otras tareas. Por lo tanto, cuanto menor sea este valor, más rápido procesará las solicitudes el hilo del servidor, pero más cargará el procesador.



recvbufsize : el tamaño del búfer que leerá el hilo del servidor a la vez.



concnt : el número máximo de conexiones con las que el subproceso del servidor funciona simultáneamente.



newcon- función de devolución de llamada que funcionará cada vez que se conecte un nuevo cliente. Los parámetros de esta función se pasarán a la conexión del cliente que se conectó.



closecon es una función de devolución de llamada que se ejecutará cada vez que se cierre una conexión inactiva. Los parámetros de esta función se pasarán a la conexión del cliente que se desconectó.



recv es una función de devolución de llamada que se llamará cuando el cliente envíe paquetes. A los parámetros de esta función se le pasará la conexión del cliente del que provienen los datos, un puntero a los datos y el tamaño del búfer con datos.



ext- función de devolución de llamada que se llamará en cada paso del bucle del hilo del servidor. Esta función está diseñada para ampliar la funcionalidad del kernel. Por ejemplo, puede vincular el procesamiento de temporizadores aquí.



La función exsc_start devuelve un identificador al hilo del servidor, que será necesario para llamar a algunas de las funciones del marco.



Envío de mensajes



La función se encarga de enviar mensajes.



void exsc_send(int des, struct exsc_excon *excon, char *buf, int bufsize);
      
      





Esta función es segura para subprocesos (puede llamarla desde cualquier subproceso). Como parámetros, debe pasarle el identificador del flujo del servidor (que recibimos como el valor de retorno de la función exsc_start ), la conexión a la que queremos enviar un mensaje, un puntero al búfer con el mensaje y el tamaño del búfer.



También tenemos la oportunidad de enviar un mensaje a un grupo de clientes. Hay una función para esto



void exsc_sendbyname(int des, char *conname, char *buf, int bufsize);
      
      





Es similar a la función exsc_send, excepto por el segundo parámetro, que es el nombre de las conexiones a las que se enviará el mensaje.



Configurar el nombre de la conexión



Para identificar más la conexión en el futuro, o almacenar alguna información sobre ella con la conexión, o enviar mensajes a un grupo de clientes, use la función



void exsc_setconname(int des, struct exsc_excon *excon, char *name);
      
      





Esta función es segura para subprocesos. El primer parámetro es el identificador del flujo del servidor, el segundo parámetro es la conexión en sí y el tercer parámetro es el nombre de esta conexión.



Conexión de un flujo de servidor a otro servidor



A veces, la lógica del lado del servidor requiere que se conecte a otro servidor para solicitar o transmitir cualquier dato. Para tales tareas, se introdujo una función que crea dicha conexión.



void exsc_connect(int des, const char *addr, uint16_t port, struct exsc_excon *excon);
      
      





Esta función es segura para subprocesos. Como parámetros necesitamos pasar el handle del flujo del servidor, la dirección del servidor al que necesitamos conectarnos, el consumo del servidor al que necesitamos conectarnos, y como último parámetro pasamos el puntero de conexión con el que podemos luego llamar a otras funciones del marco. Vale la pena señalar que no es necesario esperar a que se produzca la conexión. Podemos llamar a las funciones exsc_connect y exsc_send una tras otra y el sistema se asegurará de que el mensaje se envíe tan pronto como pueda conectarse al servidor remoto.



Servidor de ejemplo con comentarios



#include <stdio.h>
#include <string.h>
#include "../exnetwork/exsc.h"

int g_des; //   

//   
void exsc_newcon(struct exsc_excon con)
{
    printf("the connection was open  %s\n", con.addr);
}

//  
void exsc_closecon(struct exsc_excon con)
{
    printf("the connection was closed  %s\n", con.addr);
}

//    
void exsc_recv(struct exsc_excon con, char *buf, int bufsize)
{
    char msg[512] = { 0 };
    memcpy(msg, buf, bufsize);
    printf("receive data from %s\n%s\n", con.addr, msg);

    if (strcmp(msg, "say hello") == 0)
    {
        strcpy(msg, "hello");
        exsc_send(g_des, &con, msg, strlen(msg));
    }
}

//    
void exsc_ext()
{
}

int main()
{
    printf("server_test_0 is started\n");

    exsc_init(2); //        

    //      7777
    //      30 
    //       10 
    //      1024 
    //      10000
    g_des = exsc_start(7777, 30, 10, 1024, 10000, exsc_newcon, exsc_closecon, exsc_recv, exsc_ext);

    //   ,      
    //       exit    ENTER
    while (1)
    {
        const int cmdmaxlen = 256;
        char cmd[cmdmaxlen];
        fgets(cmd, cmdmaxlen, stdin);
        if (strcmp(cmd, "exit\n") == 0)
        {
            break;
        }
    }
    return 0;
}

      
      





Conclusión



El kernel exsc solo tiene un nivel bajo de interacción con los clientes. Aunque este es el elemento más importante del sistema servidor, la base sobre la que se construye todo, además de él, es necesario construir niveles superiores que se encargarán de administrar conexiones, generar mensajes, ensamblar mensajes (que probablemente vendrán en varias etapas). Si este artículo tiene una respuesta positiva, se escribirá una segunda parte, que desarrollará el tema del desarrollo de un programa de servidor de alto nivel basado en este kernel.



PD

Si alguien decide comprender la lógica interna de este marco o lo aplica en sus proyectos y encuentra errores o cuellos de botella en él, háganoslo saber. La comunidad es para eso, para que todos los que puedan contribuir a proyectos de código abierto.



Enlace a la biblioteca El



ejemplo se encuentra en el archivo exsc_test_0.zip



All Articles