Bei der Verwendung von PHP für die Socket -Programmierung stoßen viele Entwickler auf ein Problem, wenn sie zum ersten Mal mit Socket_accept () in Kontakt kommen :. Dies kann in einigen Szenarien zu einem Engpass werden, in dem hohe Parallelität oder mehrere Verbindungen gleichzeitig verarbeitet werden.
Warum passiert das? Wie können wir Socket_Select () verwenden, um dieses Problem zu blockieren und anmutig zu lösen?
Socket_accept () ist eine Funktion, mit der eine Verbindungsanforderung aus einem Hörbuchsen angenommen wird. Der Prototyp ist wie folgt:
resource socket_accept(resource $socket);
Die Essenz dieser Funktion lautet: Wenn keine Client -Verbindung besteht, blockiert sie die Programmausführung, bis eine Verbindung kommt . Dies ist ein typisches Blockierungs -E/A -Verhalten.
Dieses Verhalten ist für Server mit Single-Threaden nicht wünschenswert. Wenn der Server blockiert, weil er auf eine Verbindung wartet, sind andere Aufgaben völlig erfolglos.
Um dieses Problem zu lösen, stellt PHP die Funktion Socket_Select () bereit, mit der Sie mehrere Sockets "anhören" können, um zu bestimmen, welche Sockets für Lese-/Schreibvorgänge bereit sind, wodurch das Blockieren und Warten vermieden wird.
int socket_select(
array &$read,
array &$write,
array &$except,
int $tv_sec,
int $tv_usec = 0
);
Sie müssen nur den Socket, den Sie anhören möchten, in das $ Read -Array und auf Call socket_select () einfügen. Wenn der Socket lesbar ist (d. H. Wenn eine Client -Verbindungsanforderung vorliegt), wird Socket_Select () zurückgegeben, damit Sie nicht blockieren, wenn Sie Socket_accept () erneut aufrufen.
Hier ist ein vollständiges serverseitiges Beispiel mit socket_select () :
<?php
set_time_limit(0);
// erstellen socket
$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($server, '0.0.0.0', 8080);
socket_listen($server);
// Setzen Sie den Nichtblockierungsmodus(Optional,Aber empfehlen)
socket_set_nonblock($server);
$clients = [];
while (true) {
$read_sockets = [$server] + $clients;
$write = $except = [];
// Hören Sie sich allen an sockets,Zeitüberschreitung ist 1 Zweite
$changed = socket_select($read_sockets, $write, $except, 1);
if ($changed === false) {
echo "socket_select() Es ist ein Fehler aufgetreten\n";
break;
}
// Es gibt eine neue Verbindungsanfrage
if (in_array($server, $read_sockets)) {
$client = socket_accept($server);
if ($client !== false) {
socket_getpeername($client, $ip, $port);
echo "Neue Verbindung von {$ip}:{$port}\n";
$clients[] = $client;
}
// aus read Entfernen Sie den Hörer aus der Liste socket
$key = array_search($server, $read_sockets);
unset($read_sockets[$key]);
}
// Prozessdaten, die angeschlossen wurden
foreach ($read_sockets as $sock) {
$data = @socket_read($sock, 1024, PHP_NORMAL_READ);
if ($data === false || trim($data) === '') {
// Kundenentzündung
$key = array_search($sock, $clients);
unset($clients[$key]);
socket_close($sock);
continue;
}
$data = trim($data);
echo "Daten erhalten:{$data}\n";
$response = "Du hast es geschickt:{$data}\n";
socket_write($sock, $response);
}
}
socket_close($server);
Socket_accept () blockiert und ist für einfache, synchrone Einzelbetriebszenarien geeignet.
Um einen Server zu erstellen, der die Parallelität unterstützt, sollte Socket_Select () verwendet werden, um den Status des Sockets anzuhören.
Mit Socket_Select () können Sie Ereignisse auf mehreren Steckdosen "warten" und das gesamte Programm aufgrund eines Blockiervorgangs vermeiden.
Es wird empfohlen, es in Verbindung mit Socket_Set_Nonblock () zu verwenden, um die Flexibilität zu verbessern.
Mit den oben genannten Methoden können Sie einen reaktionsschnellen PHP -Socket -Server implementieren, auf dem mehrere Client -Verbindungen gleichzeitig verarbeitet werden können, um die Grundlage für komplexere Netzwerkprogramme zu legen.
In der tatsächlichen Entwicklung wird der Domain -Name oder die Domain -Adresse durch eine eigene Serviceadresse ersetzt, beispielsweise: