Position actuelle: Accueil> Derniers articles> Pourquoi socket_accept () continue-t-il de bloquer? Comment utiliser socket_select () pour éviter le blocage et résoudre ce problème?

Pourquoi socket_accept () continue-t-il de bloquer? Comment utiliser socket_select () pour éviter le blocage et résoudre ce problème?

M66 2025-06-12

Lorsque vous utilisez PHP pour la programmation de socket, de nombreux développeurs rencontrent un problème lorsqu'ils entrent en contact avec socket_accept () :. Cela peut devenir un goulot d'étranglement dans certains scénarios où la concurrence élevée ou les connexions multiples sont traitées simultanément.

Alors, pourquoi cela se produit-il? Comment pouvons-nous utiliser socket_select () pour éviter le blocage et résoudre gracieusement ce problème?

1. Pourquoi le bloc socket_accept () ?

socket_accept () est une fonction utilisée pour accepter une demande de connexion à partir d'une prise d'écoute. Le prototype est le suivant:

 resource socket_accept(resource $socket);

L'essence de cette fonction est: lorsqu'il n'y a pas de connexion client, il bloque l'exécution du programme jusqu'à ce qu'une connexion arrive . Il s'agit d'un comportement d'E / S de blocage typique.

Ce comportement n'est pas souhaitable pour les serveurs à thread unique. Si le serveur bloque car il attend une connexion, d'autres tâches seront complètement infructueuses.

2. Comment utiliser socket_select () pour éviter le blocage?

Pour résoudre ce problème, PHP fournit la fonction socket_select () , qui peut "écouter" sur plusieurs sockets pour déterminer les prises prêtes pour les opérations de lecture / écriture, évitant ainsi le blocage et l'attente.

Utilisation de base de socket_select ()

 int socket_select(
    array &$read,
    array &$write,
    array &$except,
    int $tv_sec,
    int $tv_usec = 0
);

Il vous suffit de mettre la prise que vous souhaitez écouter dans le tableau $ lecture et d'appeler socket_select () . Lorsque la prise est lisible (c'est-à-dire lorsqu'il y a une demande de connexion client), socket_select () reviendra, afin que vous ne bloquez pas si vous appelez Socket_Accept () .

Exemple de code

Voici un exemple complet côté serveur utilisant socket_select () :

 <?php
set_time_limit(0);

// créer socket
$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($server, '0.0.0.0', 8080);
socket_listen($server);

// Définir le mode non bloquant(Facultatif,Mais recommander)
socket_set_nonblock($server);

$clients = [];

while (true) {
    $read_sockets = [$server] + $clients;
    $write = $except = [];

    // Écoutez tout sockets,Le délai d&#39;attente est 1 Deuxième
    $changed = socket_select($read_sockets, $write, $except, 1);

    if ($changed === false) {
        echo "socket_select() Une erreur s&#39;est produite\n";
        break;
    }

    // Il y a une nouvelle demande de connexion
    if (in_array($server, $read_sockets)) {
        $client = socket_accept($server);
        if ($client !== false) {
            socket_getpeername($client, $ip, $port);
            echo "Nouvelle connexion à partir de {$ip}:{$port}\n";
            $clients[] = $client;
        }
        // depuis read Supprimer l&#39;auditeur de la liste socket
        $key = array_search($server, $read_sockets);
        unset($read_sockets[$key]);
    }

    // Traiter les données qui ont été connectées
    foreach ($read_sockets as $sock) {
        $data = @socket_read($sock, 1024, PHP_NORMAL_READ);
        if ($data === false || trim($data) === '') {
            // Déconnexion du client
            $key = array_search($sock, $clients);
            unset($clients[$key]);
            socket_close($sock);
            continue;
        }

        $data = trim($data);
        echo "Données reçues:{$data}\n";

        $response = "Tu l&#39;as envoyé:{$data}\n";
        socket_write($sock, $response);
    }
}
socket_close($server);

3. Résumé

  • socket_accept () bloque et convient aux scénarios simples et synchrones uniques;

  • Pour créer un serveur qui prend en charge la concurrence, socket_select () doit être utilisé pour écouter l'état de la prise;

  • Socket_Select () vous permet de "attendre" des événements sur plusieurs sockets et évite que l'intégralité du programme se bloque en raison d'une opération de blocage;

  • Il est recommandé de l'utiliser conjointement avec socket_set_nonblock () pour améliorer la flexibilité.

Grâce aux méthodes ci-dessus, vous pouvez implémenter un serveur de socket PHP réactif qui peut gérer plusieurs connexions client en même temps, en jetant les bases d'une programmation réseau plus complexe.

Dans le développement réel, le nom ou l'adresse de domaine est remplacé par sa propre adresse de service, par exemple: