当前位置:网站首页>Introduction de l'API commune de programmation de socket et mise en œuvre de socket, select, Poll et epoll
Introduction de l'API commune de programmation de socket et mise en œuvre de socket, select, Poll et epoll
2022-07-07 18:11:00 【Cheems】
socketUtilisation courante de la programmationapiIntroduction etsocket、select、poll、epollMise en œuvre de code de modèle de serveur hautement simultané
Préface
Cet article vise à apprendre socket Le contenu du bloc de programmation réseau ,epollC'est la priorité., Les articles suivants sont écrits reactor Le modèle est basé sur epollAu - dessus.
Les points de connaissance de cette colonne sont passés par L'éducation au son zéro Pour apprendre en classe , Faites un résumé et écrivez l'article ,C'est exact.c/c++linux Lecteurs intéressés par le cours ,Vous pouvez cliquer sur le lien C/C++ Introduction au cours avancé sur les serveurs de fond Services pour une vue détaillée des cours .
socketProgrammation
socketIntroduction
Les communications inter - processus traditionnelles sont fournies par le noyau IPCLe mécanisme fonctionne, Mais seulement pour la communication Native , Pour communiquer entre eux , Doit utiliser la communication réseau ( Essentiellement avec le noyau -Le noyau fournitsocket Le mécanisme des faux fichiers permet la communication ---- En fait, en utilisant des descripteurs de fichiers ), Cela nécessite l'utilisation du noyau fourni à l'utilisateur socket APIBibliothèque de fonctions.
UtilisersocketVa créer unsocket pair,Comme le montre la figure ci - dessous:, Un descripteur de fichier manipule deux tampons .
UtilisersocketDeAPI Fonctions pour écrire des programmes côté serveur et côté client
Connaissances préparatoires
Ordre des octets réseau
Ordre des octets réseau: Concepts de grande et de petite extrémité
- Grande extrémité: L'adresse de bas niveau stocke les données de haut niveau, Les adresses de haut niveau stockent les données de bas niveau
- Petit bout: L'adresse de bas niveau stocke les données de bas niveau , L'adresse de haut niveau stocke les données de haut niveau
Utilisation de grandes et de petites extrémités : Dans le réseau, il est souvent nécessaire de considérer le grand et le petit terminal est IPEt les ports. La transmission réseau est à grande échelle , L'ordinateur utilise une petite extrémité , Il faut donc convertir la taille
En bas4 Les fonctions sont celles qui font la conversion de taille , Nom de la fonction hReprésente l'hôtehost, nReprésente le réseaunetwork, sReprésentationshort, lReprésentationlong.
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
Les fonctions ci - dessus , Si vous n'aviez pas besoin d'une fonction de conversion interne, vous ne feriez pas de conversion .
IPFonction de conversion d'adresse
IPFonction de conversion d'adresse
int inet_pton(int af, const char *src, void *dst);
- p-> Forme de chaîne représentant la décimale pointillée
- to->À
- n->ReprésentationnetworkRéseau
Description de la fonction: Décimale pointillée sous forme de chaîne IP Réseau converti en mode grand terminal IP(Remodelage4Nombre d'octets)
Description des paramètres:
- af: AF_INET
- src: Point décimal sous forme de chaîne IPAdresse
- dst: L'adresse où la variable convertie est stockée
- Par exemple
inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);
On peut aussi calculer manuellement : Par exemple:192.168.232.145, D'abord.4 Nombre positif converti en 16Nombre décimal,
192—>0xC0 168—>0xA8 232—>0xE8 145—>0x91
Enfin, dans l'ordre des grands octets : 0x91E8A8C0, C'est4 Valeurs de forme des octets .
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
Description de la fonction: RéseauIP Convertir en chaîne décimale pointillée IP
Description des paramètres:
- af: AF_INET
- src: La forme du réseau IPAdresse
- dst: Après conversionIPAdresse, Généralement un tableau de chaînes
- size: dstLongueur
Valeur de retour:
- Succès–Retour à l'exécutiondstPointeur vers
- Échec–RetourNULL, Et la mise en placeerrno
Par exemple: IPL'adresse est010aa8c0, Conversion au format décimal point :
01---->1 0a---->10 a8---->168 c0---->192
Parce que depuis le réseau IP L'adresse est en mode haut de gamme , Donc la conversion en décimale dot devrait être : 192.168.10.1
struct sockaddr
socketStructures importantes pour la programmation:struct sockaddr
//struct sockaddrDescription de la structure:
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
//struct sockaddr_inStructure:
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
}; //Ordre des octets réseauIP--Mode grand terminal
Adoptionman 7 ip Vous pouvez voir les instructions
PrincipalAPIDescription de la fonction
socket
int socket(int domain, int type, int protocol);
Description de la fonction: Créationsocket
Description des paramètres:
- domain: Version du Protocole
- - AF_INET IPV4
- - AF_INET6 IPV6
- - AF_UNIX AF_LOCAL La prise locale utilise
- type:Type de protocole
- - SOCK_STREAM Type de flux, Le Protocole par défaut estTCPAccord
- - SOCK_DGRAM Type de rapport , Par défautUDPAccord
- protocal:
- - Remplissage général0, Indique que le Protocole par défaut du type correspondant est utilisé .
- Valeur de retour:
- - Succès: Renvoie un plus grand que0Descripteur de fichier pour
- - Échec: Retour-1, Et la mise en placeerrno
Quand on appellesocketAprès la fonction, Renvoie un descripteur de fichier, Le noyau fournit un tampon de lecture et d'écriture correspondant au descripteur de fichier, Il y a deux files d'attente en même temps, File d'attente de connexion demandée et file d'attente connectée( Pour écouter les descripteurs de fichiers ,listenFd)
bind
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
Description de la fonction: Oui.socketDescripteurs de fichiers etIP,PORTBIND
Description des paramètres:
- socket: AppelezsocketDescripteur de fichier retourné par la fonction
- addr: Du serveur local IPAdresse etPORT,
struct sockaddr_in serv;
serv.sin_family = AF_INET;
serv.sin_port = htons(8888);
//serv.sin_addr.s_addr = htonl(INADDR_ANY);
//INADDR_ANY: Indique l'utilisation de toute disponibilité valide de cet ordinateurIP
inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);
- addrlen: addr Taille de la mémoire utilisée par la variable
Valeur de retour:
- Succès: Retour0
- Échec: Retour-1, Et la mise en placeerrno
listen
int listen(int sockfd, int backlog);
Description de la fonction: Changez la prise de la dynamique primaire à la dynamique par
Description des paramètres:
- sockfd: AppelezsocketDescripteur de fichier retourné par la fonction
- backlog: InlinuxDans le système, Ceci représente la file d'attente de connexion complète ( File d'attente connectée )Nombre de.InunixType de système, Ceci représente la file d'attente de connexion complète ( File d'attente connectée )+ File d'attente semi - connectée( Demande de connexion à la file d'attente )Total
Valeur de retour:
- Succès: Retour0
- Échec: Retour-1, Et la mise en placeerrno
accept
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
Description de la fonction:Obtenir une connexion, Si aucune connexion n'est actuellement disponible, l'attente sera bloquée.
Paramètre de fonction:
- sockfd: AppelezsocketDescripteur de fichier retourné par la fonction
- addr: Paramètres sortants, Enregistrer l'adresse du client
- addrlen: Paramètres entrants et sortants, addrTaille de la mémoire occupée par la variable
Valeur de retour:
- Succès: Renvoie un nouveau descripteur de fichier,Pour communiquer avec les clients
- Échec: Retour-1, Et la mise en placeerrnoValeur.
acceptLa fonction est une fonction de blocage, S'il n'y a pas de nouvelle demande de connexion, Est toujours bloqué.
Obtenir une nouvelle connexion de la file d'attente connectée, .Et obtenir un nouveau descripteur de fichier, Ce descripteur de fichier est utilisé pour communiquer avec le client. (Le noyau est responsable d'amener les connexions dans la file d'attente de demande dans la file d'attente connectée)
connect
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
Description de la fonction: Connexion au serveur
Paramètre de fonction:
- sockfd: AppelezsocketDescripteur de fichier retourné par la fonction
- addr: Adresse du serveur
- addrlen: addr Taille de la mémoire de la variable
Valeur de retour:
- Succès: Retour0
- Échec: Retour-1, Et la mise en placeerrnoValeur
Lire et envoyer des données
Ensuite, vous pouvez utiliserwriteEtread La fonction lit et écrit .En plus d'utiliserread/writeEn dehors de la fonction, Peut également être utilisérecvEtsendFonctions.
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//Correspondant àrecvEtsendCes deux fonctionsflagsRemplissez directement0C'est bon
Attention!: Si le tampon d'écriture est plein, writeÇa bloque aussi, readEn lisant l'opération, L'absence de données dans le tampon de lecture peut causer un blocage .
Modèle de serveur hautement simultané-select
selectIntroduction
MulticanalIOTechnique: select, Écouter plusieurs descripteurs de fichiers en même temps, Laisser les opérations surveillées au noyau pour traitement
int select(int nfds, fd_set * readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
Type de donnéesfd_set::Collection de descripteurs de fichiers—— L'essence est bitmap
Description de la fonction: Le noyau délégué surveille la lecture du descripteur de fichier,Écrire ou faire une erreur
Description des paramètres:
- nfds: Le plus grand descripteur de fichier+1
- readfds: Lire la collection, Est un paramètre entrant et sortant
Entrée: Indique au noyau quels descripteurs de fichiers doivent être surveillés
Sortie: Le noyau indique à l'application quels descripteurs de fichiers ont changé
- writefds: Écrire une collection de descripteurs de fichiers(Paramètres entrants et sortants,Ibid.)
- execptfds: Collection de descripteurs de fichiers d'exception(Paramètres entrants et sortants,Ibid.)
- timeout:
NULL--Indique un blocage permanent, Jusqu'à ce qu'un incident se produise
0 --Indique qu'il n'y a pas de blocage, Reviens tout de suite., Qu'un événement surveillé se produise ou non
>0 --Retour à l'événement spécifié ou si un événement s'est produit
- Valeur de retour: Nombre de descripteurs de fichiers modifiés retournés avec succès.Échec retourné-1, Et la mise en placeerrnoValeur.
select-api
Oui.fdDeset Effacer dans la collection
void FD_CLR(int fd, fd_set *set);
Description de la fonction: JugementfdDans la collection
Valeur de retour: SifdInsetEnsemble, Retour1, Sinon, retournez à0
int FD_ISSET(int fd, fd_set *set);
Oui.fdSet tosetEnsemble
void FD_SET(int fd, fd_set *set);
InitialisationsetEnsemble
void FD_ZERO(fd_set *set);
Avecselect La fonction est en fait de confier au noyau la tâche de nous aider à détecter quels descripteurs de fichiers ont des données lisibles ,Writable,Erreur survenue
int select(int nfds, fd_set * readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
selectAvantages et inconvénients
selectAvantages:
- selectSupport multiplateforme
selectInconvénients:
- Difficultés d'écriture du Code
- Il s'agit d'une copie aller - retour de la zone utilisateur à la zone du noyau
- Lorsque le client a plusieurs connexions, Mais quelques cas actifs, selectMoins efficace(Par exemple: Dans un cas extrême, 3-1023Tous les descripteurs de fichiers sont ouverts, Mais seulement1023Il y a des données envoyées, selectC'est inefficace)
- Soutien maximal1024Connexions client(selectSoutien maximal1024Les connexions client ne sont pas supportées par des tables de descripteurs de fichiers jusqu'à1024Limite des descripteurs de fichiers, Mais parFD_SETSIZE=1024Restreint)
FD_SETSIZE=1024 fd_setLa macro a été utilisée, Bien sûr, vous pouvez modifier le noyau, Puis recompiler le noyau, Ce n'est généralement pas recommandé
selectMise en œuvre du Code
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <pthread.h>
#define MAX_LEN 4096
int main(int argc, char **argv) {
int listenfd, connfd, n;
struct sockaddr_in svr_addr;
char buff[MAX_LEN];
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
memset(&svr_addr, 0, sizeof(svr_addr));
svr_addr.sin_family = AF_INET;
svr_addr.sin_addr.s_addr = htonl(INADDR_ANY);
svr_addr.sin_port = htons(8081);
if (bind(listenfd, (struct sockaddr *) &svr_addr, sizeof(svr_addr)) == -1) {
printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
if (listen(listenfd, 10) == -1) {
printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
//select
fd_set rfds, rset, wfds, wset;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(listenfd, &rfds);
int max_fd = listenfd;
while (1) {
rset = rfds;
wset = wfds;
int nready = select(max_fd + 1, &rset, &wset, NULL, NULL);
if (FD_ISSET(listenfd, &rset)) {
//
struct sockaddr_in clt_addr;
socklen_t len = sizeof(clt_addr);
if ((connfd = accept(listenfd, (struct sockaddr *) &clt_addr, &len)) == -1) {
printf("accept socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
FD_SET(connfd, &rfds);
if (connfd > max_fd) max_fd = connfd;
if (--nready == 0) continue;
}
int i = 0;
for (i = listenfd + 1; i <= max_fd; i++) {
if (FD_ISSET(i, &rset)) {
//
n = recv(i, buff, MAX_LEN, 0);
if (n > 0) {
buff[n] = '\0';
printf("recv msg from client: %s\n", buff);
FD_SET(i, &wfds);
}
else if (n == 0) {
//
FD_CLR(i, &rfds);
close(i);
}
if (--nready == 0) break;
}
else if (FD_ISSET(i, &wset)) {
send(i, buff, n, 0);
FD_SET(i, &rfds);
FD_CLR(i, &wfds);
}
}
}
close(listenfd);
return 0;
}
Modèle de serveur hautement simultané-poll
pollIntroduction
pollSuivez - moi.selectSimilaire, Surveillance multiplex IO, Mais...pollImpossible de traverser la plateforme.En fait...pollC'est ça.select Trois ensembles de descripteurs de fichiers sont devenus une collection .
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
Description des paramètres:
- fds: Paramètres entrants et sortants, En fait, c'est un tableau de structures
fds.fd: Descripteurs de fichiers à surveiller
fds.events:
POLLIN---->Lire l'événement
POLLOUT---->Écrivez l'événement
fds.revents: Événements retournés
- nfds: Nombre de contenus réellement valides dans le tableau
- timeout: Temps mort, En millisecondes.
-1:Blocage permanent, Jusqu'à ce que l'événement surveillé se produise
0: Qu'un événement se produise ou non , Reviens tout de suite.
>0: Jusqu'à ce que l'événement surveillé se produise ou s'arrête
Valeur de retour:
- Succès: Nombre d'événements de préparation retournés
- Échec: Retour-1.Sitimeout=0, poll La fonction n'est pas bloquée , Et aucun événement ne s'est produit , Retour à-1, Eterrno=EAGAIN, Cette situation ne doit pas être considérée comme une erreur .
struct pollfd {
int fd; /* file descriptor */ Descripteurs de fichiers surveillés
short events; /* requested events */ Événements à surveiller ---Ne sera pas modifié
short revents; /* returned events */ Renvoie un événement modifié --- Retour du noyau
};
Description:
- QuandpollQuand la fonction revient, Dans la structurefdEteventsIl n'y a pas eu de changement, Y a - t - il eu des incidents causés par reventsPour juger, Alors...poll Oui demande et retour séparés
- struct pollfdDans la structurefd Membre si la valeur attribuée est -1, Etpoll Pas de surveillance
- Par rapport àselect, poll Aucun changement essentiel ; MaispollPeut percer1024Limites.In/proc/sys/fs/file-max Voir ce qu'un processus peut ouvrir socket Limite supérieure du descripteur , Le profil peut être modifié si nécessaire : /etc/security/limits.conf,Ajouter les informations de configuration suivantes, Le redémarrage du terminal prend effet
* soft nofile 1024
* hard nofile 100000
softEthardReprésente séparémentulimit Limites minimales et maximales que la commande peut modifier
pollMise en œuvre du Code
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <pthread.h>
#define MAX_LEN 4096
#define POLL_SIZE 1024
int main(int argc, char **argv) {
int listenfd, connfd, n;
struct sockaddr_in svr_addr;
char buff[MAX_LEN];
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
memset(&svr_addr, 0, sizeof(svr_addr));
svr_addr.sin_family = AF_INET;
svr_addr.sin_addr.s_addr = htonl(INADDR_ANY);
svr_addr.sin_port = htons(8081);
if (bind(listenfd, (struct sockaddr *) &svr_addr, sizeof(svr_addr)) == -1) {
printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
if (listen(listenfd, 10) == -1) {
printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
//poll
struct pollfd fds[POLL_SIZE] = {
0};
fds[0].fd = listenfd;
fds[0].events = POLLIN;
int max_fd = listenfd;
int i = 0;
for (i = 1; i < POLL_SIZE; i++) {
fds[i].fd = -1;
}
while (1) {
int nready = poll(fds, max_fd + 1, -1);
if (fds[0].revents & POLLIN) {
struct sockaddr_in client = {
};
socklen_t len = sizeof(client);
if ((connfd = accept(listenfd, (struct sockaddr *) &client, &len)) == -1) {
printf("accept socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
printf("accept \n");
fds[connfd].fd = connfd;
fds[connfd].events = POLLIN;
if (connfd > max_fd) max_fd = connfd;
if (--nready == 0) continue;
}
//int i = 0;
for (i = listenfd + 1; i <= max_fd; i++) {
if (fds[i].revents & POLLIN) {
n = recv(i, buff, MAX_LEN, 0);
if (n > 0) {
buff[n] = '\0';
printf("recv msg from client: %s\n", buff);
send(i, buff, n, 0);
}
else if (n == 0) {
//
fds[i].fd = -1;
close(i);
}
if (--nready == 0) break;
}
}
}
}
Modèle de serveur hautement simultané-epoll (Points saillants)
epollIntroduction
Déléguer la détection des changements dans les descripteurs de fichiers au noyau pour le traitement, Le noyau changera ensuite le descripteur de fichier correspondant à ÉvénementsRetour à la demande.
N'oublie pas,epollEst axé sur les événements, Sa structure de données sous - jacente est un arbre Rouge et noir ,Rouge et noirkey- Oui.fd,valC'est un événement., Retour à l'événement .
epollIl existe deux modes de fonctionnement,ETEtLTMode.
Déclenchement horizontalLT:
- High Level Representative1
- Tant qu'il y a des données dans le tampon, Je n'arrête pas de dire
Déclencheur de bordET:
- Les changements de niveau représentent 1
- La présence de données dans le tampon n'est notifiée qu'une seule fois, Avant que de nouvelles données arrivent (Si vous n'avez pas fini de lire les données, Les données restantes ne seront pas notifiées, Jusqu'à ce que de nouvelles données arrivent)
epollDéclenchement horizontal par défautLT, Dans les scénarios qui exigent des performances élevées , Peut être changé en bord ET Approche non bloquante pour améliorer l'efficacité .
Utilisation généraleLT C'est une lecture ponctuelle. , Plus de données . Et une seule fois peut lire , Les petites quantités de données utilisent des bords ET.
ET Le mode n'est notifié qu'une seule fois , Alors, lisez en boucle pendant que vous lisez , Jusqu'à la fin, Mais après la lecture readÇa va bloquer, Le descripteur de fichier doit donc être réglé en mode non - blocage (fcntlFonctions)
read Lorsque la fonction est lue en mode non - bloquant , En cas de retour-1, EterrnoPourEAGAIN, Indique que la ressource actuelle n'est pas disponible , Ce qui signifie que le tampon n'a pas de données ( Les données du tampon ont été lues ); Ou quandreadLorsque la longueur des données lues retournées est inférieure à la longueur des données demandées, Vous pouvez vous assurer qu'il n'y a plus de données lisibles dans le tampon , Vous pouvez également considérer que l'événement de lecture a été traité à ce stade .
epollRéacteur
Réacteur: Un petit événement déclenche une série de réactions
epoll L'esprit du réacteur : c++L'idée d'encapsulation de( Encapsuler les données et les opérations )
- Descripteur,Événements, Les traitements correspondants sont encapsulés
- Quand l'événement correspondant au descripteur se produit , Appel automatique à la méthode de traitement ( En fait, le principe est la fonction de rappel )
epoll L'idée centrale du réacteur est : En appelantepoll_ctlEn fonction, Oui.events En montant dans l'arbre ,Utilisationepoll_data_tDeptrMembres, Mettez un descripteur de fichier, Les événements et les fonctions de rappel sont encapsulés dans une structure , Et laissezptr Pointez vers cette structure .Puis appelezepoll_waitQuand la fonction revient, Vous pouvez obtenir des détails events, Et obtenireventsDans la structureevents.data.ptrPointeur, ptr Il y a une fonction de rappel dans la structure pointée par le pointeur , Cette fonction de rappel peut éventuellement être appelée .
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
epoll-api
int epoll_create(int size);
Description de la fonction: Créer une racine d'arbre
Description des paramètres:
- size: Nombre maximum de noeuds, Ce paramètre estlinux 2.6.8Ignoré, Mais vous devez passer un0Nombre de,Importance historique,Avecepoll_create1Ça marche..
- Valeur de retour:
Succès: Renvoie un plus grand que0Descripteur de fichier pour, Représentant la racine de l'arbre entier.
Échec: Retour-1, Et la mise en placeerrnoValeur.
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
Description de la fonction: Le noeud à écouter estepollAjouter à l'arbre, Supprimer et modifier
Description des paramètres:
epfd: epollRacines
op:
EPOLL_CTL_ADD: Ajouter un noeud d'événement à l'arbre
EPOLL_CTL_DEL: Supprimer le noeud d'événement de l'arbre
EPOLL_CTL_MOD: Modifier le noeud d'événement correspondant sur l'arbre
- fd: Descripteur de fichier correspondant au noeud d'événement
- event: Noeud d'événement à utiliser
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
- event.eventsLes plus courants sont::
EPOLLIN: Lire l'événement
EPOLLOUT: Écrivez l'événement
EPOLLERR: Événements d'erreur
EPOLLET: Mode de déclenchement du bord
- event.fd: Descripteur de fichier correspondant à l'événement à surveiller
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
Description de la fonction: Attendre que l'événement de retour du noyau se produise
Description des paramètres:
- epfd: epollRacines
- events: Paramètres sortants, En fait, c'est un tableau de structures d'événements
- maxevents: Taille du tableau
- timeout:
-1: Indique un blocage permanent
0: Retour immédiat
>0: Indique un délai d'attente pour l'événement
Valeur de retour:
- Succès: Renvoie le nombre d'événements qui se sont produits
- Échec: Sitimeout=0, Aucun événement n'est retourné ; Retour-1, ParamètreserrnoValeur
epoll_waitDeeventsEst un paramètre sortant, Appelezepoll_ctl Quelles valeurs sont passées au noyau , Quandepoll_waitAu retour, Ce que le noyau renvoie ,C'est vrai.struct event Modifier la valeur de la variable structure pour .
epollAvantages et inconvénients
epollAvantages:
- Haute performance, Un million de concurrents. ,EtselectPas question.
epollInconvénients:
- Impossible de traverser la plateforme,linuxEn bas
epollMise en œuvre du Code
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <pthread.h>
#define POLL_SIZE 1024
#define MAX_LEN 4096
int main(int argc, char **argv) {
int listenfd, connfd, n;
char buff[MAX_LEN];
struct sockaddr_in svr_addr;
memset(&svr_addr, 0, sizeof(svr_addr));
svr_addr.sin_family = AF_INET;
svr_addr.sin_addr.s_addr = htonl(INADDR_ANY);
svr_addr.sin_port = htons(8081);
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
if (bind(listenfd, (struct sockaddr *) &svr_addr, sizeof(svr_addr)) == -1) {
printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
if (listen(listenfd, 10) == -1) {
printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
int epfd = epoll_create(1); //int size
struct epoll_event events[POLL_SIZE] = {
0};
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = listenfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
while (1) {
int nready = epoll_wait(epfd, events, POLL_SIZE, 5);
if (nready == -1) {
continue;
}
int i = 0;
for (i = 0; i < nready; i++) {
int actFd = events[i].data.fd;
if (actFd == listenfd) {
struct sockaddr_in cli_addr;
socklen_t len = sizeof(cli_addr);
if ((connfd = accept(listenfd, (struct sockaddr *) &cli_addr, &len)) == -1) {
printf("accept socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
printf("accept\n");
ev.events = EPOLLIN;
ev.data.fd = connfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
}
else if (events[i].events & EPOLLIN) {
n = recv(actFd, buff, MAX_LEN, 0);
if (n > 0) {
buff[n] = '\0';
printf("recv msg from client: %s\n", buff);
send(actFd, buff, n, 0);
}
else if (n == 0) {
//
epoll_ctl(epfd, EPOLL_CTL_DEL, actFd, NULL);
close(actFd);
}
}
}
}
return 0;
}
边栏推荐
- mui侧边导航锚点定位js特效
- 如何在软件研发阶段落地安全实践
- js拉下帷幕js特效显示层
- What skills can you master to be a "master tester" when doing software testing?
- 开发一个小程序商城需要多少钱?
- 漫画 | 宇宙第一 IDE 到底是谁?
- [principle and technology of network attack and Defense] Chapter 1: Introduction
- Please insert the disk into "U disk (H)" & unable to access the disk structure is damaged and cannot be read
- 2021-06-28
- In depth understanding of USB communication protocol
猜你喜欢
JS pull down the curtain JS special effect display layer
Yearning-SQL审核平台
运行yolo v5-5.0版本报错找不到SPPF错误,进行解决
目标管理【管理学之十四】
Deep learning machine learning various data sets summary address
SD_DATA_RECEIVE_SHIFT_REGISTER
使用OneDNS完美解决办公网络优化问题
Deep learning - make your own dataset
Mobile app takeout ordering personal center page
[OKR target management] value analysis
随机推荐
目标管理【管理学之十四】
自动化测试:Robot FrameWork框架大家都想知道的实用技巧
Pro2:修改div块的颜色
2021年全国平均工资出炉,你达标了吗?
Understanding of 12 methods of enterprise management
Yarn capacity scheduler (ultra detailed interpretation)
Management by objectives [14 of management]
Mui side navigation anchor positioning JS special effect
Run Yolo v5-5.0 and report an error. If the sppf error cannot be found, solve it
性能测试过程和计划
Cartoon | who is the first ide in the universe?
golang 客户端服务端登录
漫画 | 宇宙第一 IDE 到底是谁?
五种网络IO模型
Explain it in simple terms. CNN convolutional neural network
[trusted computing] Lesson 11: TPM password resource management (III) NV index and PCR
深度学习机器学习各种数据集汇总地址
Mobile pixel bird game JS play code
Year SQL audit platform
debian10编译安装mysql