Lors de la création de services côté serveur PHP de haute performance, il est souvent nécessaire d'utiliser des modèles multi-thread ou multi-processus pour gérer les connexions simultanées. La programmation de socket est un moyen important d'atteindre cet objectif. Cependant, lors de la manipulation des connexions de socket, les paramètres du blocage et du non-bloquant deviennent essentiels. Les fonctions socket_set_block () et socket_set_nonblock () fournies par PHP peuvent être utilisées pour contrôler ce comportement. Les utiliser raisonnablement peut empêcher les threads ou les processus d'être coincés en raison du blocage des E / S, de l'amélioration de la stabilité et de la réactivité des services.
Cet article présentera comment utiliser correctement la fonction socket_set_block () dans un service PHP multi-thread ou multi-processus pour éviter de bloquer les problèmes et expliquer ses scénarios d'application et les meilleures pratiques en combinaison avec des exemples de code spécifiques.
Par défaut, Socket bloque. Lorsque vous appelez une fonction comme socket_read () ou socket_accept () dans une prise de blocage, s'il n'y a pas de données à lire ou qu'il n'y a pas de nouvelle connexion, l'appel attendra que la condition soit satisfaite.
Ce n'est pas un problème dans le modèle unique, mais dans un environnement multi-thread ou multi-processus, si un fil d'enfant ou un processus d'enfant ne peut pas libérer des ressources à temps en raison du blocage, cela peut entraîner un gaspillage de ressources ou même le programme sera mort.
Les prises non bloquantes n'attendront pas, elles reviendront immédiatement et s'il n'y a actuellement pas de données, une erreur sera renvoyée (généralement Eagain ou EwouldBlock ). Vous pouvez obtenir le code d'erreur et le traiter via socket_last_error () .
socket_set_block () est utilisé pour définir le socket sur le mode de blocage, tandis que sa fonction inverse socket_set_nonblock () est utilisée pour définir le mode non bloquant.
Dans le multithreading ou le multiprocessement, les stratégies recommandées sont:
Dans le processus principal ou le processus parent, la prise d'écoute adopte un mode non bloquant pour éviter d'accepter le blocage;
Dans un thread enfant ou un processus enfant, une connexion client unique peut être transférée en mode de blocage pour faciliter le traitement de la logique de demande complète;
Dans les boucles d'événements ou les modes à l'aide de select () et de stream_select () , il est recommandé de maintenir le mode non bloquant.
Voici un exemple de service PHP basé sur un modèle multi-processus qui montre comment utiliser correctement socket_set_block () pour éviter les problèmes de blocage:
<code> & lt ;? php set_time_limit (0); $ host = '0.0.0.0';
$ port = 9000;
// Créer une prise
$ server = socket_create (af_inet, sock_stream, sol_tcp);
socket_bind ($ server, $ host, $ port);
socket_Listeten ($ serveur);
socket_set_nonblock ($ serveur); // Définissez la prise principale sur le mode non bloquant
echo "Server a démarré sur {$ host}: {$ port} \ n";
while (true) {
$ client = @socket_accept ($ serveur);
if ($client === false) {
usleep(100000); // éviterCPUInactif
continue;
}
$pid = pcntl_fork();
if ($pid == -1) {
die("Fork failed\n");
} elseif ($pid == 0) {
// Sous-processus
socket_close($server); // Sous-processus不需要监听Socket
socket_set_block($client); // Configuration du clientSocketEn mode blocage
$input = socket_read($client, 1024);
$output = strtoupper(trim($input));
socket_write($client, "You said: $output\n");
socket_close($client);
exit(0);
} else {
// Processus parental
socket_close($client); // Processus parental不处理客户端Socket
pcntl_wait($status, WNOHANG); // éviter僵尸进程
}
}
?>
</code>
Dans cet exemple, le processus principal utilise une prise non bloquante pour attendre la connexion, en évitant le blocage socket_accept () ; Dans le processus enfant, nous changeons la prise qui interagit avec le client en mode de blocage, ce qui facilite le traitement séquentiel de l'entrée et de la sortie, et la logique est plus simple et plus fiable.
Ne définissez pas le bloc et le non-block pour alterner la commutation sur une prise en même temps , car cela peut entraîner la confusion de l'État. Il est plus facile de gérer des processus ou des threads qui définissent les responsabilités.
L'écoute de plusieurs prises non bloquantes à l'aide de Select () est un moyen plus efficace de s'adapter à un modèle axé sur les événements.
Les fonctions Stream_Socket_ * de la série de PHP fournissent une encapsulation plus conviviale dans certains scénarios et peuvent également être utilisées avec Stream_Set_Blocking () pour contrôler le comportement de blocage.
Ne paniquez pas lorsque les codes d'erreur comme "la ressource temporairement indisponible" apparaissent. Il s'agit de l'une des caractéristiques des prises non bloquantes et doit être résolue par le biais de reprise logique ou de sondage d'événements.
L'utilisation rationnelle de socket_set_block () et socket_set_nonblock () est la clé pour construire des services de réseau PHP efficaces. En particulier dans un environnement multi-thread ou multi-processus, la clarification des responsabilités et la définition des modes de blocage appropriés peuvent non seulement éviter les problèmes de blocage des threads / processus, mais également améliorer la vitesse de réponse du service et la stabilité.
Grâce aux exemples et stratégies ci-dessus, je crois que vous pouvez mieux utiliser ces fonctions de socket dans des projets réels pour créer un service d'arrière-plan PHP robuste. Si vous construisez un service GIT privé ou une plate-forme de communication en temps réel comme <code> gitbox.net </code>, le contrôle précis du socket est une partie indispensable.