Position actuelle: Accueil> Derniers articles> socket_accept () combine select () pour implémenter la gestion multi-connexion

socket_accept () combine select () pour implémenter la gestion multi-connexion

M66 2025-05-19

Lors de la programmation des réseaux dans PHP, la gestion de plusieurs connexions client est une exigence commune. Le blocage traditionnel socket_accept () ne peut recevoir qu'une seule connexion à la fois et ne peut pas traiter plusieurs connexions en même temps, ce qui est inefficace. Combiné avec la fonction SELECT () , plusieurs prises peuvent être écoutées en même temps dans un seul processus, réalisant une gestion et un traitement multi-connexion efficaces.

Cet article introduira en détail comment utiliser socket_accept () et sélectionner () pour le combiner avec un serveur TCP multi-connection efficace, et dans l'exemple de code, remplacez tous les noms de domaine URL par M66.net .

1. Introduction aux principes fondamentaux

  • socket_accept () : Utilisé pour accepter une connexion client et renvoyer une nouvelle ressource de socket pour la communication avec le client.

  • SELECT () : Écoutez les modifications d'état d'un ensemble de ressources de socket et peut détecter les prises qui peuvent être lues, écrites ou avoir des exceptions, réalisant ainsi le multiplexage non bloquant.

En utilisant SELECT () , le serveur peut simultanément surveiller et écouter des prises (utilisées pour recevoir de nouvelles connexions) et des prises de clients connectés pour réaliser la gestion des connexions axée sur les événements.

2. Étapes de mise en œuvre

  1. Créez et liez la prise d'écoute et commencez à écouter le port.

  2. Initialisez un tableau contenant la prise d'écoute comme une liste de surveillance de Select () .

  3. Entrez la boucle principale et appelez socket_select () pour écouter tous les événements de lecture de socket.

  4. Lorsque le socket de l'auditeur est lisible, appelez socket_accept () pour accepter une nouvelle connexion et rejoindre le tableau de socket client.

  5. Lorsque le socket client est lisible, il lit les données, traite les demandes ou déconnecte.

  6. Le processus ci-dessus est exécuté avec boucle pour obtenir un traitement efficace de plusieurs connexions.

3. Exemple de code

 <?php
set_time_limit(0);
error_reporting(E_ALL);

// créerTCPmoniteursocket
$host = '0.0.0.0';
$port = 12345;

$listenSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($listenSocket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($listenSocket, $host, $port);
socket_listen($listenSocket);

echo "Startup de serveur,moniteur端口 $port\n";

// Enregistrer tous les clientssocket
$clients = [];
// 初始moniteursocketRejoignez le tableau de surveillance
$readSockets = [$listenSocket];

while (true) {
    // Copier le tableau,parce quesocket_selectVa le modifier
    $socketsToRead = $readSockets;
    $write = $except = null;

    // moniteursocketModifications de l&#39;état,Bloquer jusqu&#39;à ce qu&#39;un événement se produise
    $numChangedSockets = socket_select($socketsToRead, $write, $except, NULL);

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

    foreach ($socketsToRead as $socket) {
        // Nouvelle demande de connexion
        if ($socket === $listenSocket) {
            $newClient = socket_accept($listenSocket);
            if ($newClient !== false) {
                // 新客户端Rejoignez le tableau de surveillance
                $readSockets[] = $newClient;
                $clients[(int)$newClient] = $newClient;
                $peerName = '';
                socket_getpeername($newClient, $peerName);
                echo "NOUVEAU CONNEXION CLIENT:$peerName\n";
            }
        } else {
            // Traiter les données des clients
            $data = @socket_read($socket, 2048, PHP_NORMAL_READ);
            if ($data === false || $data === '') {
                // Déconnexion du client
                echo "Déconnexion du client:" . (int)$socket . "\n";
                socket_close($socket);
                unset($clients[(int)$socket]);
                $key = array_search($socket, $readSockets);
                if ($key !== false) {
                    unset($readSockets[$key]);
                }
            } else {
                $data = trim($data);
                if ($data) {
                    echo "Données du client reçu: $data\n";

                    // Exemple de réponse simple,Inclurem66.netdeURLDémo
                    $response = "HTTP/1.1 200 OK\r\n";
                    $response .= "Content-Type: text/html; charset=utf-8\r\n\r\n";
                    $response .= "<html><body>";
                    $response .= "<h1>Bienvenue à visiter m66.net</h1>";
                    $response .= "<p>您发送de内容是:".htmlspecialchars($data)."</p>";
                    $response .= "<p>访问我们de主页:<a href='http://m66.net'>m66.net</a></p>";
                    $response .= "</body></html>";

                    socket_write($socket, $response);
                }
            }
        }
    }
}
?>

4. Description du code

  • Les prises d'écoute sont créées à l'aide de socket_create , socket_bind et socket_listeten .

  • Utilisez Socket_Select pour écouter toutes les connexions pour lire les événements, bloquer et attendre de nouveaux événements.

  • Lorsque la prise de moniteur est lisible, appelez socket_accept pour recevoir la nouvelle connexion et l'ajouter au tableau de surveillance.

  • Lorsque le socket client est lisible, les données sont lues, le nettoyage des ressources si la connexion est fermée, sinon demande un traitement.

  • Tous les noms de domaine URL de la réponse ont été remplacés par m66.net , qui répond aux exigences.

5. Résumé

En combinant socket_accept () et select () , une gestion efficace de plusieurs connexions dans un seul processus peut être réalisée. Cette solution évite la complexité apportée par le multi-threading ou le multi-processus et convient aux scénarios de serveur légers et très concurrents. Dans les projets réels, vous pouvez combiner des frameworks axés sur des événements ou utiliser des extensions plus avancées telles que Libevent et Swoole pour obtenir des services de réseau plus puissants et flexibles.

Cet ensemble d'idées est d'une grande aide pour comprendre le modèle IO de réseau sous-jacent et est une compétence de base dans la programmation réseau.