Bonjour à tous! Je souhaite partager avec le public le cadre sur la base duquel il existe actuellement de nombreux serveurs desservant des milliers de clients dans divers systèmes de serveurs. exsc (EXtensible Server Core) est un framework écrit en C et vous permet d'avoir un ou plusieurs threads de serveur dans une application. Chaque thread serveur est capable de servir un grand nombre de clients. Bien que le framework puisse être utilisé dans un modèle de demande-réponse, il a été principalement conçu pour maintenir une connexion constante avec un grand nombre de clients et échanger des messages en temps réel. Puisque j'aime moi-même prendre un projet HelloWorld prêt à l'emploi, le compiler et voir comment tout fonctionne, à la fin de l'article, je posterai un lien vers un tel projet.
De nombreuses opérations sont effectuées pour une connexion spécifique. Dans le cadre de ce cadre, la structure exsc_excon est responsable de la connexion. Cette structure comprend les champs suivants:
ix - index de connexion. Il s'agit du numéro de série de la connexion qui était libre au moment où le client s'est connecté.
id - identifiant de connexion. Il s'agit d'un numéro de connexion unique. Contrairement à un index, il ne se répète pas.
addr -
nom de l' adresse IP du client - nom de la connexion. Plusieurs connexions peuvent être nommées avec le même nom, puis un message peut être envoyé à toutes les connexions avec le même nom (voir la fonction exsc_sendbyname).
Initialisation du noyau
Afin de travailler avec le noyau, nous devons l'initialiser en utilisant la fonction
void exsc_init(int maxsrvcnt);
Le paramètre maxsrvcnt indique au noyau le nombre de threads serveur que nous utiliserons dans notre application.
Démarrage du flux du serveur
Ensuite, nous devons démarrer le flux du serveur à l'aide de la fonction
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());
port - le port qui écoutera le flux du serveur.
timeout - indique combien de temps le thread du serveur attendra toute activité du client. Si pendant ce temps le client n'a envoyé aucun message, le thread serveur ferme une telle connexion. Par conséquent, si nous voulons garder une connexion constante et définir ce paramètre par exemple 30 secondes, il est nécessaire d'envoyer un message ping toutes les 10 à 15 secondes.
Plage de temps- la période pendant laquelle nous autorisons l'exécution de la requête. Par exemple, si cette valeur est définie sur 100 millisecondes et que le thread du serveur a traité toutes les demandes actuelles des utilisateurs en 10 secondes, il laissera les 90 millisecondes restantes au processeur pour effectuer d’autres tâches. Ainsi, plus cette valeur est petite, plus le thread serveur traitera les requêtes rapidement, mais plus il chargera le processeur.
recvbufsize - la taille du tampon que le thread du serveur lira à la fois.
concnt - le nombre maximum de connexions avec lesquelles le thread serveur fonctionne simultanément.
newcon- fonction de rappel qui fonctionnera à chaque fois qu'un nouveau client se connecte. Les paramètres de cette fonction seront transmis à la connexion du client qui s'est connecté.
closecon est une fonction de rappel qui s'exécute chaque fois qu'une connexion inactive est fermée. Les paramètres de cette fonction seront passés à la connexion du client qui s'est déconnecté.
recv est une fonction de rappel qui sera appelée lorsque le client envoie des paquets. Les paramètres de cette fonction seront passés la connexion du client d'où proviennent les données, un pointeur vers les données et la taille du tampon avec les données.
ext- fonction de rappel qui sera appelée à chaque passage de la boucle de thread du serveur. Cette fonction est faite pour étendre les fonctionnalités du noyau. Par exemple, vous pouvez lier le traitement des minuteries ici.
La fonction exsc_start renvoie un handle vers le thread du serveur, qui sera nécessaire pour appeler certaines des fonctions du framework.
Envoi de messages
La fonction est responsable de l'envoi des messages.
void exsc_send(int des, struct exsc_excon *excon, char *buf, int bufsize);
Cette fonction est thread-safe (vous pouvez l'appeler à partir de n'importe quel thread). En tant que paramètres, vous devez lui passer le handle du flux serveur (que nous avons reçu comme valeur de retour de la fonction exsc_start ), la connexion à laquelle nous voulons envoyer un message, un pointeur vers le tampon avec le message et la taille du tampon.
Nous avons également la possibilité d'envoyer un message à un groupe de clients. Il y a une fonction pour cela
void exsc_sendbyname(int des, char *conname, char *buf, int bufsize);
Elle est similaire à la fonction exsc_send, sauf pour le deuxième paramètre, qui est le nom des connexions auxquelles le message sera envoyé.
Définition du nom de la connexion
Afin d'identifier plus précisément la connexion à l'avenir, ou stocker des informations à son sujet avec la connexion, ou envoyer des messages à un groupe de clients, utilisez la fonction
void exsc_setconname(int des, struct exsc_excon *excon, char *name);
Cette fonction est thread-safe. Le premier paramètre est le handle du flux du serveur, le deuxième paramètre est la connexion elle-même et le troisième paramètre est le nom de cette connexion.
Connexion d'un flux de serveur à un autre serveur
Parfois, la logique côté serveur vous oblige à vous connecter à un autre serveur pour demander ou transmettre des données. Pour de telles tâches, une fonction a été introduite qui crée une telle connexion.
void exsc_connect(int des, const char *addr, uint16_t port, struct exsc_excon *excon);
Cette fonction est thread-safe. En tant que paramètres, nous devons passer le handle du flux du serveur, l'adresse du serveur auquel nous devons nous connecter, la consommation du serveur auquel nous devons nous connecter, et comme dernier paramètre, nous passons le pointeur de connexion avec lequel nous pouvons appelez plus tard d'autres fonctions du framework. Il est à noter que nous n'avons pas besoin d'attendre que la connexion ait lieu. Nous pouvons appeler les fonctions exsc_connect et exsc_send l'une après l'autre et le système s'assurera que le message est envoyé dès qu'il pourra se connecter au serveur distant.
Exemple de serveur avec commentaires
#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;
}
Conclusion
Le noyau exsc n'effectue qu'un faible niveau d'interaction avec les clients. Bien que ce soit l'élément le plus important du système serveur, la base sur laquelle tout est construit, en plus de cela, vous devez créer des niveaux plus élevés qui seront responsables de la gestion des connexions, de la génération des messages, de l'assemblage des messages (qui viendront probablement plusieurs étapes). Si cet article a une réponse positive, une deuxième partie sera rédigée, qui développera le sujet du développement d'un programme serveur de niveau supérieur basé sur ce noyau.
PS
Si quelqu'un décide de comprendre la logique interne de ce cadre ou de l'appliquer dans ses projets et y trouve des bogues ou des goulots d'étranglement, veuillez nous en informer. La communauté est pour ça, pour que tous ceux qui peuvent contribuer à des projets open source.
Lien vers la bibliothèque L'
exemple se trouve dans l'archive exsc_test_0.zip