1. Connaissances de base
1.1 Swoole
Swoole est PHP asynchrone pour l'environnement de production réseau moteur de communication, les développeurs PHP peuvent utiliser Swoole pour développer des services serveur hautes performances. La partie serveur de Swoole a beaucoup de contenu et implique de nombreux points de connaissances. Cet article ne donne qu'un bref aperçu de son serveur. Les détails spécifiques de la mise en œuvre seront présentés en détail dans les articles suivants.
Recommandé (gratuit) : swoole
1.2 Programmation réseau
1. Il s'agit de démarrer un (ou plusieurs) processus sur une (ou plusieurs) machines, d'écouter sur un (ou plusieurs) ports et de suivre un certain protocole (il peut s'agir du protocole standard http, dns ; il peut également s'agir d'un protocole autonome). protocole défini) Échanger des informations avec les clients.
2. La programmation réseau actuelle est principalement basée sur des protocoles TCP, UDP ou de couche supérieure. La partie serveur de Swoole est basée sur les protocoles TCP et UDP.
3. La programmation via udp est relativement simple. Cet article présente principalement la programmation réseau basée sur le protocole TCP
4. La programmation réseau TCP implique principalement 4 types d'événements
● Établissement de la connexion : Désigne principalement le client initiant une connexion (connect) et le serveur acceptant la connexion (accepter)
Quantity Arrivée du message : Le serveur reçoit les données envoyées par le client. Cet événement est l'événement le plus important dans la programmation réseau TCP. Lorsque le serveur gère ce type d'événement, il peut utiliser des méthodes bloquantes ou non bloquantes. , les problèmes du serveur tels que le sous-emballage et les tampons de la couche application doivent également être pris en compte
lég Message envoyé avec succès : Envoyé avec succès signifie que la couche application envoie les données avec succès aux mots du socket du noyau dans le tampon d'envoi ne signifie pas que le client a reçu les données avec succès. Pour les services à faible trafic, les données peuvent généralement être envoyées en une seule fois, et il n'est pas nécessaire de se soucier de tels événements. Si toutes les données ne peuvent pas être envoyées au tampon du noyau en même temps, vous devez vous assurer que le message est envoyé avec succès (pour bloquer la programmation, l'envoi est réussi après le retour de l'appel système (write, writev, send, etc.), tandis que pour une programmation non bloquante, vous devez considérer la situation réelle. Si les données écrites sont conformes aux attentes)
● Connexion déconnectée : Vous devez considérer le client déconnexion (la lecture renvoie 0) et déconnexion du serveur (fermeture, arrêt)
5 Le processus d'établissement d'une connexion TCP est comme indiqué ci-dessous
● Dans. sur la figure, ACK et SYN représentent les bits d'indicateur, seq et ack sont le numéro de séquence du paquet TCP et le numéro de séquence de confirmation
6 Le processus de déconnexion TCP est comme indiqué ci-dessous
<.>
● La figure ci-dessus considère que lorsque le client se déconnecte activement, le serveur se déconnecte activement est également similaire
● Dans la figure, FIN et ACK représentent des bits d'indicateur, seq et ack sont le numéro de séquence du paquet TCP et le numéro de séquence de confirmation
1.3 Communication inter-processus
1. comprend des canaux sans nom (pipe), des canaux nommés (fifo), des signaux (signal) et des sémaphores (semaphore), un socket (socket), une mémoire partagée (mémoire partagée) et d'autres méthodes
2. sockets (un type de socket) pour la communication entre plusieurs processus Communication (faisant référence aux processus internes de Swoole)
1.4 socketpair
1.4 socketpair est utilisé pour créer une paire de sockets, similaire à pipe , la différence est que pipe est une communication unidirectionnelle et que la communication bidirectionnelle doit être créée deux fois pour obtenir une communication bidirectionnelle. sockets sont utilisés, la méthode d'échange de données peut également être définie
2 Une fois l'appel système socketpair
est appelé avec succès, sv[. 0] et sv[1] stockent respectivement un descripteur de fichier - Écrivez dans sv[0], vous pouvez lire à partir de sv[1]
- Écrivez dans sv[1], vous pouvez lire. from sv[0]
- Le processus appelle socketpair Après avoir bifurqué le processus enfant, le processus enfant héritera des deux descripteurs de fichiers sv[0] et sv[1] par défaut, permettant ainsi la communication entre le parent et l'enfant processus. Par exemple, le processus parent écrit dans sv[0] et le processus enfant lit dans sv[1] ; le processus enfant écrit dans sv[1] et le processus parent lit dans sv[0]
-
1.5 Démon
1 Le démon est un processus d'arrière-plan spécial, qui est séparé du terminal et utilisé pour effectuer périodiquement une certaine tâche
.
2. Groupe de processus
Chaque processus appartient à un groupe de processus- Chaque groupe de processus a un numéro de groupe de processus, c'est-à-dire le numéro de processus (PID) du chef de groupe.
- Un processus ne peut définir le numéro de groupe de processus que pour lui-même ou ses processus enfants
-
Session
.
- Une session peut contenir plusieurs groupes de processus. Il peut y avoir au plus un groupe de processus de premier plan dans ces groupes de processus (ou aucun), et les autres sont des groupes de processus d'arrière-plan
- Une session ne peut contenir que plusieurs groupes de processus. avoir au plus un groupe de processus. Un terminal de contrôle
- Lorsqu'un utilisateur se connecte via le terminal ou le réseau, une nouvelle session sera créée
- Le processus appelle l'appel système setsid pour créer un nouvelle session. Le processus appelant setsid ne peut pas être un certain processus. Le leader du groupe. Une fois l'appel setsid terminé, le processus devient le premier processus (processus principal) de la session et devient le leader d'un nouveau groupe de processus. Si le processus avait auparavant un terminal de contrôle, la connexion entre le processus et le terminal est également déconnectée.
4. Comment créer un processus démon
- Après avoir forké le processus enfant, le processus parent se termine, le processus enfant exécute setsid et le processus enfant peut devenir un processus démon. De cette façon, le processus enfant est le processus leader de la session et peut rouvrir le terminal. A ce moment, il peut à nouveau fork. Le processus enfant généré par fork ne peut plus ouvrir le terminal (seul le processus leader de la session le peut). ouvrez le terminal). Le deuxième fork n'est pas nécessaire, c'est juste pour empêcher le processus enfant d'ouvrir à nouveau le terminal
- Linux fournit la fonction démon (cette fonction n'est pas un appel système, mais une fonction de bibliothèque) pour créer un processus démon
1.6 Exemple de serveur TCP Swoole
- Lorsque le code ci-dessus est exécuté en mode cli, l'opcode est généré par analyse lexicale et analyse syntaxique, puis transmis à la machine virtuelle zend pour exécution
- Lorsque la machine virtuelle zend exécute $serv->start(), elle démarre le serveur Swoole
- Le rappel d'événement défini dans le code ci-dessus est dans l'exécution du processus de travail, le modèle de serveur Swoole sera présenté en détail plus tard Mode
1 Description
. Le mode de base adopte un modèle multi-processus, cohérent avec nginx. Chaque processus n'a qu'un seul thread, et le processus principal est responsable de la gestion du processus de travail. Le processus de travail est responsable de l'écoute du port, de l'acceptation des connexions et du traitement des demandes. et fermer les connexions
Si plusieurs processus écoutent le port en même temps, il y aura un problème de groupe tonitruant
Le noyau Linux 3.9 et les versions ultérieures fournissent un nouveau paramètre de socket SO_REUSEPORT, qui permet à plusieurs processus de se lier au même port lorsque le noyau reçoit une nouvelle demande de connexion, il réveille l'un d'entre eux pour le traitement. également être fait au niveau, ce qui peut résoudre le problème du groupe tonitruant mentionné ci-dessus. Swoole a également ajouté ce paramètre En mode base, le paramètre réacteur_number n'a aucun effet pratique
Si le nombre. des processus de travail est défini sur 1, alors le processus de travail ne sera pas bifurqué et le processus principal gère directement la demande. Ce mode convient au débogage
- 2. 🎜>
Le code php est exécuté sur $serv- >Lorsque start(), le processus principal entre dans la fonction int swServer_start(swServer *serv), qui est responsable du démarrage du serveur- Dans la fonction swServer_start, swReactorProcess_start seront appelés. Cette fonction créera plusieurs processus de travail
-
Le processus principal et le processus de travail entrent chacun dans leurs propres boucles d'événements pour gérer divers événements-
- 2.2. mode processus
1. Description
- Ce mode est multi-processus et multithread, avec le processus principal, le processus gestionnaire, le processus de travail et le processus task_worker
-
Il existe plusieurs threads sous le processus principal. Le thread principal est chargé d'accepter les connexions, puis de les transmettre pour réagir aux demandes. Le thread de réaction est responsable de la réception des paquets de données, de la transmission des données au processus de travail pour traitement, puis du traitement des données renvoyées par le processus de travail - processus gestionnaire. Ce processus est un seul thread et est principalement responsable de. gérer le processus de travail, similaire à nginx. Processus principal, lorsque le processus de travail se termine anormalement, le processus gestionnaire est responsable de la redistribution d'un processus de travail
processus de travail, qui est un processus à thread unique et est responsable du traitement spécifique des demandes processus task_worker, pour le traitement Pour les tâches plus chronophages, il n'est pas activé par défaut
Le processus de travail communique avec le thread de réaction du processus principal à l'aide de sockets de domaine , et il n'y a aucune communication entre les processus de travail
- 2. Processus de démarrage
- Entrée de démarrage du serveur Swoole : fonction swServer_start
-
-
-
- Si le mode démon est défini, vérifiez les paramètres nécessaires. Après cela, transformez-vous d'abord en processus démon, puis forkez le processus gestionnaire, puis créez un thread de réacteur
Le principal Le processus exécute d'abord le processus gestionnaire, et le processus gestionnaire est responsable de l'élimination du processus de travail et du processus task_worker. Une fois que le processus de travail entre dans int swWorker_loop
(swServer *serv, int work_id), c'est-à-dire qu'il entre dans sa propre boucle d'événements, il en va de même pour task_worker, qui entre dans sa propre boucle d'événements
Le processus principal pthread_create le thread de réaction, le thread principal et le thread de réaction entrent chacun dans leur propre boucle d'événements, le thread du réacteur exécute static int swRea-torThread_loop (swThreadParam *param), en attendant le traitement des événements
- 3. Schéma de structure
-
- La structure du mode de processus Swoole est illustrée dans la figure ci-dessous,
La figure ci-dessus ne prend pas en compte le processus task_worker par défaut. des processus task_worker est 0
3. Processus de traitement des demandes (mode processus)
3.1 Communication entre le thread du réacteur et processus de travail
1. La communication entre le processus maître Swoole et le processus de travail est comme indiqué dans la figure ci-dessous
- Swoole utilise SOCK_DGRAM, pas SOCK_STREAM , en effet, chaque thread de réacteur est responsable du traitement de plusieurs requêtes. Après avoir reçu la requête, le réacteur transmettra les informations au processus de travail, qui est responsable du traitement. Si SOCK_STREAM est utilisé, le processus de travail ne peut pas. sous-traiter TCP puis traiter la demande
- La fonction swFactoryProcess_start créera un nombre correspondant de paires de sockets en fonction du nombre de processus de travail pour la communication entre le thread du réacteur et le processus de travail (voir la fonction swPipeUnsock_create pour plus de détails)
2. Supposons que le réacteur ait 2 threads et 3 processus de travail. La communication entre le réacteur et le travailleur est comme indiqué dans la figure ci-dessous
Chaque thread de réacteur est chargé de surveiller plusieurs processus de travail, chaque processus de travail n'a qu'un seul thread de réacteur à l'écoute (reactor_num <= work_num). Par défaut, Swoole utilise worker_process_id % réacteur_num pour allouer les processus de travail et les transmettre au thread de réacteur correspondant pour surveillance - Le thread de réacteur traitera les données après avoir reçu les données d'un processus de travail. ce thread de réacteur peut Ce n'est pas le thread de réacteur qui a envoyé la requête.
-
3. Paquets de données pour la communication entre le thread du réacteur et le processus de travail
3.2 Traitement des demandes
1. Le thread principal du processus maître est chargé d'écouter le port (), d'accepter les connexions (listen
, générer un fd) et d'attribuer la requête au thread du réacteur après avoir accepté la connexion par défaut. , il est alloué via fd % réacteur_number, puis via accept
Ajouter fd au thread de réacteur correspondant et écouter l'événement d'écriture lors de sa première connexion. Parce que le tampon d'écriture du socket créé par la connexion nouvellement acceptée est vide, il doit l'être. inscriptible et sera déclenché immédiatement, puis le thread du réacteur effectuera certaines opérations d'initialisation epoll_ctl
Il existe des situations où plusieurs threads exploitent un epollfd (créé via l'appel système - ) en même temps. .
epoll_create
Il est thread-safe que plusieurs threads appellent - en même temps (correspondant à un epollfd ), un thread est en cours d'exécution et les autres threads seront bloqués (à cause de l'arborescence rouge-noir sous-jacente). epoll doit être utilisé en même temps)
epoll_ctl
Il est également thread-safe d'appeler plusieurs threads en même temps- , mais un événement peut être traité par plusieurs threads qui le reçoivent en même temps. En pratique, il n'est pas recommandé que plusieurs threads
epoll_wait
epollfd en même temps. Cette situation n'existe pas dans Swoole. Chaque thread de réacteur dans Swoole a son propre epollfdepoll_wait
Un thread appelle - et un thread appelle
epoll_wait
Selon le manuel de l'utilisateur, si epoll_ctl
est. nouveau Le fd ajouté est prêt, ce qui rendra le thread en cours d'exécution epoll_ctl
non bloquant (vous pouvez visualiser le contenu pertinent via man epoll_wait
) epoll_wait
2 . L'événement d'écriture de fd dans le thread du réacteur est déclenché et le thread du réacteur est responsable du traitement. S'il s'avère que c'est la première fois qu'il se joint et qu'il n'y a aucune donnée à écrire, la surveillance des événements de lecture sera. activé et prêt à accepter les données envoyées par le client 3. thread du réacteur Lire les données de la demande de l'utilisateur, Après avoir reçu une donnée demandée, transmettre les données au processus de travail, la valeur par défaut est pour l'attribuer via fd % worker_number
le réacteur l'envoie au travailleur Le paquet de données du processus contiendra un en-tête, qui enregistre les informations du réacteur- Si les données envoyées sont trop grande, les données doivent être fragmentées. En raison des limitations d'espace, la fragmentation des données sera effectuée plus tard. Décrivez en détail
- Il peut y avoir plusieurs threads de réacteur envoyant des données au même processus de travail en même temps, donc Swoole. utilise le mode SOCK_DGRAM pour communiquer avec le processus de travail. Grâce à l'en-tête de chaque paquet de données, le processus de travail peut distinguer Les données envoyées par quel thread de réacteur peuvent également être connues quelle requête
-
4. Le processus reçoit le paquet de données envoyé par le réacteur, il le traite. Une fois le traitement terminé, le résultat de la demande est envoyé au processus principal
Le paquet de données envoyé par le processus de travail au processus principal. comprendra également un en-tête lorsque le thread du réacteur reçoit le paquet de données, il peut connaître le thread du réacteur correspondant, le fd demandé et d'autres informations-
5. processus de travail, qui déclenchera le traitement d'un thread de réacteur
- Ce thread de réacteur n'est pas nécessairement le thread de réacteur qui a précédemment envoyé la requête au processus de travail
- Chaque thread de réacteur du processus principal est responsable du suivi des données envoyées par le package de processus de travail, chaque paquet de données envoyé par le travailleur ne sera surveillé que par un seul thread de réacteur, donc un seul thread de réacteur sera déclenché
6. par le processus de travail. Si c'est directement Pour envoyer des données au client, vous pouvez les envoyer directement. Si vous devez modifier l'état d'écoute de cette connexion (comme close
), vous devez d'abord trouver le thread du réacteur qui. surveille cette connexion, puis modifie l'état d'écoute de cette connexion (en appelant epoll_ctl
>)
- Le thread de traitement du réacteur et le thread d'écoute du réacteur peuvent ne pas être le même thread
- Le thread d'écoute du réacteur est chargé de surveiller les données envoyées par le client, puis de les transmettre au processus de travail
- Le thread de traitement du réacteur est chargé de surveiller les données envoyées par le processus de travail au processus principal, puis envoyer les données au client
4. Débogage GDB
4.1 Démarrage en mode processus
4.2 Démarrage en mode de base
Résumé et réflexions
1. Cet article présente principalement les deux modes du serveur Swoole : le mode de base et le mode processus, et explique en détail les modèles de programmation réseau des deux modes, et se concentre sur la méthode de communication inter-processus, requête flux de traitement, etc. en mode processus
2. En mode processus, pourquoi ne pas créer plusieurs threads directement dans le processus principal et laisser les threads gérer directement les requêtes (cela peut éviter la surcharge de communication inter-processus ? ), mais créer un processus gestionnaire, puis le processus gestionnaire crée un processus de travail, et le processus de travail gère la demande ?
- Personnellement, je pense que cela peut être le support de PHP pour le multi-threading. n'est pas très convivial, et la plupart de PHP n'effectue qu'une programmation monothread
- Bien que le TSRM fourni par ZendVM prenne également en charge l'environnement multi-thread, c'est en fait une solution pour isoler la mémoire par thread, et le multi-threading est cela n'a aucun sens
3. En mode processus, chaque thread de réacteur du processus principal peut gérer plusieurs requêtes en même temps. Plusieurs requêtes sont traitées simultanément. Nous le regardons sous deux dimensions
Du point de vue du processus principal, le processus principal traite plusieurs requêtes en même temps. Lorsque tous les paquets de requêtes sont reçus, ils sont transmis au processus de travail pour traitement - Du point de vue d'un processus principal. Processus de travail, ce processus de travail Les demandes reçues sont en série. Par défaut, le processus de travail traite également les demandes en série. Si une seule demande est bloquée (le processus de travail de Swoole rappellera la fonction de traitement des événements écrite par PHPer, ce qui peut bloquer), les demandes suivantes. ne pourra pas traiter, c'est le problème du blocage de la file d'attente. Dans ce cas, la coroutine de Swoole peut être utilisée grâce à la planification de la coroutine, lorsqu'une seule requête est bloquée, le processus de travail peut continuer à traiter d'autres requêtes
- 4. Utiliser Swoole Lors de la création d'un serveur TCP, puisque TCP est un protocole de flux d'octets, il doit être sous-traité, et Swoole ne peut pas sous-traiter sans connaître le protocole de communication entre le client et le serveur. En mode processus, les données. transmis par le réacteur au processus de travail. Il ne peut s'agir que d'un flux d'octets et doit être traité par l'utilisateur. Bien sûr, en général, il n'est pas nécessaire de créer un protocole par vous-même. En utilisant le serveur TCP, Swoole prend déjà en charge Http, Https et d'autres protocoles
.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!