Position actuelle: Accueil> Derniers articles> Comment obtenir une réception non bloquante avec socket_recv avec socket_select? Code joint

Comment obtenir une réception non bloquante avec socket_recv avec socket_select? Code joint

M66 2025-06-22

Dans les fonctions PHP, socket_recv et socket_select sont des outils très courants dans la programmation réseau, surtout lorsque vous devez effectuer des opérations d'E / S non bloquantes. En utilisant ces deux fonctions, vous pouvez éviter le blocage causé par l'attente des données du réseau, améliorant ainsi l'efficacité et la réactivité de votre programme. Cet article présentera en détail comment utiliser ces deux fonctions pour obtenir une réception non bloquante.

1. Qu'est-ce que la réception non bloquante?

Dans la réception de blocage traditionnelle, lorsque vous utilisez Socket_Recv et d'autres fonctions pour recevoir des données, le programme s'arrêtera sur cette ligne de code et ne continuera pas à exécuter jusqu'à ce que les données arrivent ou que le délai d'attente se produise. Cela signifie que si aucune donnée n'arrive, le programme sera "coincé" et aucune autre opération ne peut être effectuée.

Au lieu de bloquer la réception, cela signifie que le programme n'arrêtera pas de s'exécuter en attendant les données. Il vérifiera lors de la réception de données. S'il n'y a pas de données, d'autres opérations peuvent être poursuivies. De cette façon, le programme ne bloquera pas en attendant les données lors de l'exécution des opérations d'E / S.

2. Utilisez la fonction Socket_Select

La fonction Socket_Select fournit un moyen de vérifier si plusieurs prises sont prêtes, ce qui peut nous aider à éviter de bloquer l'attente. Lorsque nous appelons Socket_Select , il vérifiera si la prise donnée a des données à lire. Si c'est le cas, il renvoie l'objet de socket correspondant. Vous pouvez utiliser cette fonction pour effectuer des opérations de réception non bloquantes sur plusieurs sockets.

Syntaxe de base de socket_select :

 <span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-title function_ invoke__">socket_select</span></span><span> ( </span><span><span class="hljs-keyword">array</span></span><span> &amp;</span><span><span class="hljs-variable">$read</span></span><span>, </span><span><span class="hljs-keyword">array</span></span><span> &amp;</span><span><span class="hljs-variable">$write</span></span><span>, </span><span><span class="hljs-keyword">array</span></span><span> &amp;</span><span><span class="hljs-variable">$except</span></span><span>, </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$tv_sec</span></span><span>, </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$tv_usec</span></span><span> )
</span></span>
  • $ Read : Un tableau contenant toutes les prises qui doivent être détectées pour être lisibles.

  • $ write : un tableau contenant toutes les sockets qui doivent être détectés pour être écrit.

  • $ sauf : un tableau contenant toutes les prises qui doivent être détectées pour des exceptions.

  • $ tv_sec et $ tv_usec : spécifie le délai d'expiration (secondes et microsecondes). S'il est réglé sur NULL , c'est une attente infinie.

Syntaxe de base de socket_recv :

 <span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-title function_ invoke__">socket_recv</span></span><span> ( resource </span><span><span class="hljs-variable">$socket</span></span><span> , </span><span><span class="hljs-keyword">string</span></span><span> &amp;</span><span><span class="hljs-variable">$buf</span></span><span> , </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$length</span></span><span> , </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$flags</span></span><span> )
</span></span>
  • $ socket : la ressource de socket pour recevoir des données.

  • $ buf : les données reçues sont stockées dans cette variable.

  • $ Longueur : le nombre maximum d'octets à recevoir.

  • $ drapeaux : drapeaux qui contrôlent l'opération de réception, généralement 0.

3. Exemple de code

Voici un exemple complet d'utilisation de socket_recv avec socket_select pour obtenir une réception non bloquante:

 <span><span><span class="hljs-meta">&lt;?php</span></span><span>
</span><span><span class="hljs-comment">// Créer un TCP socket</span></span><span>
</span><span><span class="hljs-variable">$server</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_create</span></span><span>(AF_INET, SOCK_STREAM, SOL_TCP);

</span><span><span class="hljs-comment">// Configuration de l&#39;adresse du serveur et du port</span></span><span>
</span><span><span class="hljs-variable">$address</span></span><span> = </span><span><span class="hljs-string">'127.0.0.1'</span></span><span>;
</span><span><span class="hljs-variable">$port</span></span><span> = </span><span><span class="hljs-number">12345</span></span><span>;

</span><span><span class="hljs-comment">// Lier socket</span></span><span>
</span><span><span class="hljs-title function_ invoke__">socket_bind</span></span><span>(</span><span><span class="hljs-variable">$server</span></span><span>, </span><span><span class="hljs-variable">$address</span></span><span>, </span><span><span class="hljs-variable">$port</span></span><span>);

</span><span><span class="hljs-comment">// Commencer à surveiller</span></span><span>
</span><span><span class="hljs-title function_ invoke__">socket_listen</span></span><span>(</span><span><span class="hljs-variable">$server</span></span><span>);

</span><span><span class="hljs-comment">// Définir le délai</span></span><span>
</span><span><span class="hljs-variable">$timeout</span></span><span> = </span><span><span class="hljs-number">10</span></span><span>;  </span><span><span class="hljs-comment">// temps mort 10 Deuxième</span></span><span>
</span><span><span class="hljs-variable">$read</span></span><span> = [</span><span><span class="hljs-variable">$server</span></span><span>];  </span><span><span class="hljs-comment">// Utilisé pour détecter s&#39;il y a une connexion</span></span><span>
</span><span><span class="hljs-variable">$write</span></span><span> = </span><span><span class="hljs-variable">$except</span></span><span> = [];

</span><span><span class="hljs-comment">// Entrez dans la boucle,En attente de la connexion du client</span></span><span>
</span><span><span class="hljs-keyword">while</span></span><span> (</span><span><span class="hljs-literal">true</span></span><span>) {
    </span><span><span class="hljs-comment">// utiliser socket_select Pour détecter s&#39;il y a une nouvelle connexion</span></span><span>
    </span><span><span class="hljs-variable">$changed</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_select</span></span><span>(</span><span><span class="hljs-variable">$read</span></span><span>, </span><span><span class="hljs-variable">$write</span></span><span>, </span><span><span class="hljs-variable">$except</span></span><span>, </span><span><span class="hljs-variable">$timeout</span></span><span>);

    </span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$changed</span></span><span> === </span><span><span class="hljs-literal">false</span></span><span>) {
        </span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"socket_select failed\n"</span></span><span>;
        </span><span><span class="hljs-keyword">break</span></span><span>;
    }

    </span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$changed</span></span><span> &gt; </span><span><span class="hljs-number">0</span></span><span>) {
        </span><span><span class="hljs-comment">// Vérifiez s&#39;il y a une nouvelle connexion client</span></span><span>
        </span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">in_array</span></span><span>(</span><span><span class="hljs-variable">$server</span></span><span>, </span><span><span class="hljs-variable">$read</span></span><span>)) {
            </span><span><span class="hljs-variable">$client</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_accept</span></span><span>(</span><span><span class="hljs-variable">$server</span></span><span>);
            </span><span><span class="hljs-variable">$read</span></span><span>[] = </span><span><span class="hljs-variable">$client</span></span><span>;  </span><span><span class="hljs-comment">// De nouvelles connexions sont ajoutées pour lire le tableau</span></span><span>
            </span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Client connected\n"</span></span><span>;
        }

        </span><span><span class="hljs-comment">// Itérer à travers tous les connectés socket,Vérifiez s&#39;il y a des données à lire</span></span><span>
        </span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$read</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$sock</span></span><span>) {
            </span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$sock</span></span><span> !== </span><span><span class="hljs-variable">$server</span></span><span>) {
                </span><span><span class="hljs-variable">$data</span></span><span> = </span><span><span class="hljs-string">''</span></span><span>;
                </span><span><span class="hljs-variable">$bytes_received</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_recv</span></span><span>(</span><span><span class="hljs-variable">$sock</span></span><span>, </span><span><span class="hljs-variable">$data</span></span><span>, </span><span><span class="hljs-number">1024</span></span><span>, MSG_DONTWAIT);
                </span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$bytes_received</span></span><span> === </span><span><span class="hljs-number">0</span></span><span>) {
                    </span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Client disconnected\n"</span></span><span>;
                    </span><span><span class="hljs-title function_ invoke__">socket_close</span></span><span>(</span><span><span class="hljs-variable">$sock</span></span><span>);
                    </span><span><span class="hljs-variable">$read</span></span><span> = </span><span><span class="hljs-title function_ invoke__">array_diff</span></span><span>(</span><span><span class="hljs-variable">$read</span></span><span>, [</span><span><span class="hljs-variable">$sock</span></span><span>]);  </span><span><span class="hljs-comment">// Supprimer ceci de la liste de lecture socket</span></span><span>
                } </span><span><span class="hljs-keyword">elseif</span></span><span> (</span><span><span class="hljs-variable">$bytes_received</span></span><span> &gt; </span><span><span class="hljs-number">0</span></span><span>) {
                    </span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Received data: <span class="hljs-subst">$data</span></span></span><span>\n";
                }
            }
        }
    }

    </span><span><span class="hljs-comment">// Plus de logique de traitement peut être ajoutée ici,Par exemple, vérifiez les opérations d&#39;écriture、temps mort处理等</span></span><span>
}

</span><span><span class="hljs-title function_ invoke__">socket_close</span></span><span>(</span><span><span class="hljs-variable">$server</span></span><span>);
</span><span><span class="hljs-meta">?&gt;</span></span><span>
</span></span>

Interprétation du code:

  1. Créer et lier socket : Créez une prise TCP à l'aide de socket_create et liez à l'adresse et au port spécifiés avec socket_bind .

  2. Socket_Select écoute plusieurs sockets : le tableau de lecture $ écouté dans socket_select , et la prise de serveur $ sera utilisée pour accepter de nouvelles connexions client. Le paramètre $ Timeout est défini sur 10 secondes, c'est-à-dire dans les 10 secondes, socket_select reviendra si aucune donnée n'est transmise ou une nouvelle connexion.

  3. Recevoir des données : s'il y a des données à lire, la réception non bloquant est effectuée via socket_recv . Si le client se déconnecte, fermez le socket correspondant et retirez-le du tableau de lecture $ .

4. Choses à noter

  • Mode non bloquant : Dans ce cas, nous avons utilisé l'indicateur MSG_DONTWAIT pour obtenir une réception non bloquante, ce qui signifie que Socket_recv ne bloquera pas le programme s'il n'y a pas de données à lire.

  • L'utilisation de socket_select : socket_select est utilisée pour vérifier l'état de plusieurs prises. En mode non bloquant, il vous aide à éviter d'attendre les données d'une prise tout le temps, mais peut être traitée immédiatement lorsque des données sont disponibles.

  • Gestion de la mémoire : Lorsque vous utilisez Socket_Select , assurez-vous de supprimer les prises fermées du tableau de lecture $ pour éviter les fuites de mémoire et la détection de socket non valide.

5. Résumé

En combinant socket_recv et socket_select , vous pouvez atteindre une réception non bloquante très commodément. Cette méthode empêche non seulement les programmes de bloquer en raison de l'attente des données, mais peut également gérer efficacement les connexions à socket multiples et obtenir une communication réseau plus efficace.

La réception non bloquante est une technologie importante, en particulier utile lors de la création de services de réseau à faible curances et à faible latence. Grâce à une utilisation flexible de la programmation de socket PHP, les performances et l'évolutivité des applications peuvent être améliorées.