Fonction PHP socket_set_blocking() : tout ce que vous devez savoir
Apprenez à contrôler le mode bloquant ou non bloquant d'un socket PHP avec socket_set_blocking(), dépréciée en PHP 8.1, et ses remplaçants modernes.
Lorsque vous écrivez du code réseau en PHP, vous devez souvent contrôler si un appel d'E/S attend des données (mode bloquant) ou retourne immédiatement (mode non bloquant). La fonction socket_set_blocking() était l'alias historique pour définir ce mode. Elle a été dépréciée en PHP 8.1 et ne doit pas être utilisée dans du nouveau code.
Le piège est que le bon remplacement dépend du type de connexion que vous avez, et c'est là que de nombreux guides se trompent :
- Si vous avez utilisé l'extension Sockets (
socket_create(), qui retourne un objetSocket), utilisezsocket_set_nonblock()etsocket_set_block(). - Si vous avez utilisé un flux (
fsockopen()oustream_socket_client(), qui retournent une ressource de flux), utilisezstream_set_blocking().
socket_set_blocking() était en réalité un alias de stream_set_blocking(), donc elle n'a jamais fonctionné que sur des ressources de flux — jamais sur des objets Socket. Cette distinction est la clé pour éviter une TypeError à l'exécution.
Mode bloquant et mode non bloquant
En mode bloquant (le mode par défaut), un appel de lecture ou d'écriture suspend l'exécution du script jusqu'à ce que l'opération puisse se terminer. Un socket_read() sur un socket vide attend simplement que des octets arrivent.
En mode non bloquant, le même appel retourne immédiatement. Si aucune donnée n'est prête, il retourne un résultat vide (ou false) au lieu d'attendre. Cela permet à un seul script de gérer plusieurs connexions ou de rester réactif — au prix d'avoir à interroger et vérifier si des données sont effectivement arrivées.
| Utilisez le mode bloquant quand… | Utilisez le mode non bloquant quand… |
|---|---|
| Vous gérez une connexion à la fois | Vous servez plusieurs clients dans une boucle |
| La simplicité prime sur le débit | Le script doit rester réactif |
| Une requête/réponse courte et prévisible | Vous implémentez votre propre boucle de sondage/événements |
Définir le mode sur un objet Socket
Si vous avez créé la connexion avec l'extension Sockets, utilisez socket_set_nonblock() et socket_set_block() :
socket_set_nonblock(Socket $socket): bool
socket_set_block(Socket $socket): boolLes deux retournent true en cas de succès et false en cas d'échec. Un exemple complet et exécutable avec gestion des erreurs et nettoyage :
<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
die("Socket creation failed: " . socket_strerror(socket_last_error()) . "\n");
}
// Switch to non-blocking mode
if (!socket_set_nonblock($socket)) {
die("Failed to set non-blocking mode\n");
}
echo "Socket is now non-blocking.\n";
// ... perform non-blocking socket operations ...
// Switch back to blocking mode if needed
socket_set_block($socket);
echo "Socket is now blocking again.\n";
socket_close($socket);N'appelez pas
stream_set_blocking($socket, false)sur un objetSocket—socket_create()retourne une instanceSocket, etstream_set_blocking()n'accepte qu'une ressource de flux. Passer un objetSocketlève uneTypeError.
Définir le mode sur un flux
Si vous avez ouvert la connexion avec fsockopen() ou stream_socket_client(), vous disposez d'une ressource de flux et devez utiliser stream_set_blocking() :
stream_set_blocking(resource $stream, bool $enable): bool$stream: la ressource de flux à configurer.$enable:truepour le mode bloquant,falsepour le mode non bloquant.
<?php
$stream = stream_socket_client('tcp://example.com:80', $errno, $errstr, 5);
if ($stream === false) {
die("Connect failed: $errstr ($errno)\n");
}
// Switch the stream to non-blocking mode
if (!stream_set_blocking($stream, false)) {
die("Failed to set non-blocking mode\n");
}
echo "Stream is now non-blocking.\n";
fclose($stream);Une boucle de lecture non bloquante
Le mode non bloquant n'est utile que si vous interrogez le socket. Un schéma typique envoie une requête, puis vérifie répétitivement la réponse sans bloquer le script :
<?php
$stream = stream_socket_client('tcp://example.com:80', $errno, $errstr, 5);
if ($stream === false) {
die("Connect failed: $errstr ($errno)\n");
}
stream_set_blocking($stream, false);
fwrite($stream, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n");
$response = '';
$start = time();
while (!feof($stream) && time() - $start < 5) {
$chunk = fread($stream, 8192);
if ($chunk === '' || $chunk === false) {
// No data yet — do other work or wait briefly
usleep(50000); // 50 ms
continue;
}
$response .= $chunk;
}
echo substr($response, 0, 15), "\n"; // e.g. "HTTP/1.1 200 OK"
fclose($stream);L'appel usleep() empêche une boucle occupée serrée de monopoliser le CPU. En production, vous remplaceriez généralement ce sondage manuel par stream_select() pour attendre efficacement sur plusieurs flux à la fois.
Notes de version
- PHP 8.1 :
socket_set_blocking()est dépréciée. L'appeler émet un avis de dépréciation. - La fonction était un alias de
stream_set_blocking(), donc elle n'a jamais accepté d'objetsSocket. - Pour les objets
Socket,socket_set_nonblock()/socket_set_block()ont toujours été les appels corrects et restent pris en charge.
Fonctions associées
socket_get_status()— inspecter l'état d'un socket, notamment s'il est bloqué.socket_set_timeout()— contrôler combien de temps une opération bloquante attend avant d'abandonner.- PHP Streams — l'API de flux plus large à laquelle appartient
stream_set_blocking().
Conclusion
Contrôler le mode bloquant d'une connexion est essentiel pour créer des applications réseau PHP réactives. La clé est d'associer la fonction au type de connexion : utilisez socket_set_nonblock() / socket_set_block() pour les objets Socket, et stream_set_blocking() pour les ressources de flux. Évitez la fonction dépréciée socket_set_blocking() dans le nouveau code, et n'oubliez pas que le mode non bloquant ne porte ses fruits que si vous l'associez à une boucle de sondage.