PHP socket_set_blocking() Funktion: Alles, was Sie wissen müssen
Erfahren Sie, wie Sie mit socket_set_blocking() und den modernen Alternativen den Blocking-Modus von PHP-Sockets und Streams steuern.
Wenn Sie Netzwerkcode in PHP schreiben, müssen Sie häufig steuern, ob ein I/O-Aufruf auf Daten wartet (blocking) oder sofort zurückkehrt (non-blocking). Die Funktion socket_set_blocking() war der historische Alias zum Setzen dieses Modus. Sie wurde in PHP 8.1 als veraltet markiert und sollte in neuem Code nicht mehr verwendet werden.
Das Besondere dabei ist, dass der richtige Ersatz davon abhängt, welche Art von Verbindung Sie verwenden, und hier liegen viele Anleitungen falsch:
- Wenn Sie die Sockets-Erweiterung (
socket_create(), die einSocket-Objekt zurückgibt) verwendet haben, nutzen Siesocket_set_nonblock()undsocket_set_block(). - Wenn Sie einen Stream (
fsockopen()oderstream_socket_client(), die eine Stream-Ressource zurückgeben) verwendet haben, nutzen Siestream_set_blocking().
socket_set_blocking() war tatsächlich ein Alias von stream_set_blocking() und funktionierte daher ausschließlich mit Stream-Ressourcen – niemals mit Socket-Objekten. Diese Unterscheidung ist der Schlüssel, um einen TypeError zur Laufzeit zu vermeiden.
Blocking- vs. Non-Blocking-Modus
Im Blocking-Modus (dem Standard) pausiert ein Lese- oder Schreibaufruf die Skriptausführung, bis die Operation abgeschlossen werden kann. Ein socket_read() auf einem leeren Socket wartet einfach, bis Bytes ankommen.
Im Non-Blocking-Modus kehrt derselbe Aufruf sofort zurück. Wenn keine Daten bereit sind, gibt er ein leeres Ergebnis (oder false) zurück, anstatt zu warten. Dies ermöglicht es einem einzelnen Skript, viele Verbindungen zu verwalten oder reaktionsfähig zu bleiben – auf Kosten des Pollens und der Prüfung, ob tatsächlich Daten angekommen sind.
| Blocking verwenden, wenn… | Non-Blocking verwenden, wenn… |
|---|---|
| Sie eine Verbindung auf einmal verwalten | Sie viele Clients in einer Schleife bedienen |
| Einfachheit wichtiger ist als Durchsatz | Das Skript reaktionsfähig bleiben muss |
| Eine kurze, vorhersehbare Anfrage/Antwort | Sie eine eigene Polling-/Ereignisschleife implementieren |
Den Modus bei einem Socket-Objekt setzen
Wenn Sie die Verbindung mit der Sockets-Erweiterung erstellt haben, verwenden Sie socket_set_nonblock() und socket_set_block():
socket_set_nonblock(Socket $socket): bool
socket_set_block(Socket $socket): boolBeide geben bei Erfolg true und bei Fehler false zurück. Ein vollständiges, ausführbares Beispiel mit Fehlerbehandlung und Aufräumen:
<?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);Rufen Sie nicht
stream_set_blocking($socket, false)auf einemSocket-Objekt auf —socket_create()gibt eineSocket-Instanz zurück, undstream_set_blocking()akzeptiert nur eine Stream-Ressource. Das Übergeben einesSocket-Objekts wirft einenTypeError.
Den Modus bei einem Stream setzen
Wenn Sie die Verbindung mit fsockopen() oder stream_socket_client() geöffnet haben, haben Sie eine Stream-Ressource und sollten stream_set_blocking() verwenden:
stream_set_blocking(resource $stream, bool $enable): bool$stream: die zu konfigurierende Stream-Ressource.$enable:truefür Blocking-Modus,falsefür Non-Blocking-Modus.
<?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);Eine Non-Blocking-Leseschleife
Non-Blocking-Modus ist nur nützlich, wenn Sie pollen. Ein typisches Muster sendet eine Anfrage und prüft dann wiederholt auf eine Antwort, ohne das Skript einzufrieren:
<?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);Der usleep()-Aufruf verhindert eine enge Busy-Loop, die die CPU blockiert. In der Produktion würden Sie dieses manuelle Polling in der Regel durch stream_select() ersetzen, um effizient auf mehrere Streams gleichzeitig zu warten.
Versionshinweise
- PHP 8.1:
socket_set_blocking()ist veraltet. Ein Aufruf gibt einen Deprecation-Hinweis aus. - Die Funktion war ein Alias von
stream_set_blocking()und akzeptierte daher niemalsSocket-Objekte. - Für
Socket-Objekte warensocket_set_nonblock()/socket_set_block()schon immer die richtigen Aufrufe und bleiben weiterhin unterstützt.
Verwandte Funktionen
socket_get_status()— den Zustand eines Sockets prüfen, einschließlich ob er blockiert ist.socket_set_timeout()— steuern, wie lange eine blockierende Operation wartet, bevor sie aufgibt.- PHP Streams — die umfangreichere Streams-API, zu der
stream_set_blocking()gehört.
Fazit
Die Steuerung des Blocking-Modus einer Verbindung ist entscheidend für die Entwicklung reaktionsfähiger PHP-Netzwerkanwendungen. Der Schlüssel liegt darin, die Funktion dem Verbindungstyp anzupassen: Verwenden Sie socket_set_nonblock() / socket_set_block() für Socket-Objekte und stream_set_blocking() für Stream-Ressourcen. Vermeiden Sie die veraltete socket_set_blocking() in neuem Code und denken Sie daran, dass der Non-Blocking-Modus nur dann sinnvoll ist, wenn Sie ihn mit einer Polling-Schleife kombinieren.