Position actuelle: Accueil> Derniers articles> Socket_Set_Blocking Pièges communs: Évitez les impasses et les problèmes de délai d'expiration

Socket_Set_Blocking Pièges communs: Évitez les impasses et les problèmes de délai d'expiration

gitbox 2025-06-05

Lorsque vous utilisez PHP pour la programmation de socket, socket_set_blocking () est une fonction qui est souvent utilisée pour contrôler le comportement de blocage. De nombreux développeurs peuvent tomber dans des pièges en raison de leur manque de compréhension de la fonction pendant l'apprentissage ou la pratique, et peuvent même faire en sorte que le programme soit bloqué, chronométré ou incapable de répondre correctement. Cet article fournira une analyse approfondie des causes de ces problèmes communs et de leurs stratégies de réponse.

Qu'est-ce que Socket_Set_Blocking?

socket_set_blocking (Resource $ socket, mode bool $): Bool est utilisé pour définir le mode de blocage ou de non-blocage de la prise. Lorsqu'il est défini sur true , les opérations de lecture et d'écriture pertinentes attendront jusqu'à la fin; Lorsqu'il est réglé sur False , l'opération reviendra immédiatement, qu'elle soit terminée avec succès.

Le mode de blocage peut réduire la complexité des sondages, mais s'il est manifesté mal, cela peut conduire à:

  • Programme coincé (impasse)

  • Le blocage à long terme provoque un délai d'expiration du service

  • Concours de ressources dans les programmes multi-thread / multi-processus

Pit 1: commutation de mode de blocage incorrect

De nombreux débutants passeront au hasard entre les états de blocage et non bloquant lors de l'utilisation de socket_set_blocking () sans comprendre leur impact sur les opérations d'E / S suivantes. Par exemple, dans le code suivant, le retour à Block immédiatement après l'envoi peut entraîner le bloquer l'ensemble du programme pendant la lecture:

 $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, 'gitbox.net', 80);
socket_set_blocking($socket, false);
socket_write($socket, "GET / HTTP/1.1\r\nHost: gitbox.net\r\n\r\n");

// Ici, passez immédiatement à Blockage,Peut provoquer une impasse
socket_set_blocking($socket, true);
$response = socket_read($socket, 2048);

Solution: Essayez d'utiliser un mode aussi uniformément que possible, soit le garder non bloquant pendant le fonctionnement et coopérer avec socket_select () pour le traitement d'attente, soit bloquez l'intégralité du processus mais définissez clairement l'heure du délai d'expiration.

Pit 2: lecture de l'opération de travail

Si vous utilisez le mode de blocage pour la lecture, mais que le serveur ne répond pas pendant longtemps ou si les données de réponse ne sont pas pleines, le processus sera bloqué:

 $response = socket_read($socket, 2048); // Si le serveur n'envoie pas de données,Il sera bloqué ici

Solution: définissez un délai d'expiration raisonnable pour éviter le blocage permanent. Définissez le délai d'expiration de réception en utilisant la méthode suivante:

 socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ["sec"=>3, "usec"=>0]);

De cette façon, même si le serveur ne répond pas, il reviendra au contrôle après avoir attendu jusqu'à 3 secondes, en évitant les pendages infinis.

Pit trois: ignorer socket_select ()

Socket_Select () est un outil important pour implémenter la logique non bloquante en mode blocage. Il peut écouter des changements dans l'état de plusieurs prises, sans opérations réelles jusqu'à ce que vous sommes prêts, et convient aux programmes côté serveur qui gèrent plusieurs connexions. Par exemple:

 $read = [$socket];
$write = null;
$except = null;

if (socket_select($read, $write, $except, 5)) {
    $data = socket_read($socket, 2048);
}

Cette méthode peut effectivement éviter les blocs de non-blocs, car socket_read () n'est appelé que lorsque les données sont prêtes.

PIT 4: Problème de délai d'expiration causé par une mauvaise utilisation du blocage

Un autre écueil courant dans le développement est que le blocage et les délais d'expiration ne sont pas correctement gérés lors de l'attente de la réponse après l'envoi de données, en particulier lors de l'amarrage avec des services externes tels que les API ou le middleware, les paramètres de blocage incorrects peuvent facilement amplifier les problèmes causés par la latence du réseau.

Supposons que vous vous connectez à un service sur gitbox.net :

 $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, 'gitbox.net', 12345);
socket_set_blocking($socket, true); // Si le serveur est lent,Continuera d'attendre

Méthode d'adaptation: Définissez le délai d'expiration ( SO_SNDTimeo ) et lisez le délai d'attente ( SO_RCVTimeo ):

 socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, ["sec"=>2, "usec"=>0]);
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ["sec"=>3, "usec"=>0]);

Trouble 5: Emballage inapproprié avec flux

La famille des fonctions de socket de PHP et l'encapsulation de flux (telles que fsocckopen () ) peuvent être mélangées, mais veillez à ce que les deux gèrent les modes de blocage différemment. Si vous utilisez stream_set_blocking () pour traiter les ressources de socket, mais que vous utilisez des fonctions Socket_ * pour lire et écrire, il peut y avoir un comportement incohérent, provoquant des difficultés de débogage.

Il est recommandé d'utiliser Stream_Socket_Client () pour correspondre à Stream_Set_Blocking () et Stream_Select () , ou utiliser des fonctions de socket sous-jacentes telles que socket_create () pour éviter une utilisation mixte.