Start · Sprachen · PHP · Referenz · stream_select

stream_select

Funktion

Führt den <code>select()</code>-Systemaufruf auf Stream-Arrays mit einem Timeout aus und überwacht mehrere Streams gleichzeitig auf Lese-, Schreib- oder Ausnahmezustände.

seit PHP 4.3.0 Kategorie: io

Signatur

stream_select(array &$read, array|null &$write, array|null &$except, int|null $seconds, int $microseconds = 0): int|false

Beschreibung

stream_select() überwacht eine Gruppe von Streams auf Aktivität und wartet, bis mindestens einer davon bereit ist oder ein Timeout abläuft. Das Prinzip entspricht dem POSIX-select()-Systemaufruf: Es können gleichzeitig Streams auf Lesbarkeit ($read), Schreibbereitschaft ($write) und Ausnahmezustände ($except) geprüft werden.

Nach dem Aufruf werden die Arrays in-place modifiziert – sie enthalten nur noch die Streams, die tatsächlich aktiv sind. Nicht aktive Streams werden aus den Arrays entfernt. Dies ermöglicht nicht-blockierendes I/O ohne Threads: Man kann in einer einzigen Schleife viele Netzwerk- oder Datei-Streams bedienen.

Ein Timeout von null bei $seconds bewirkt, dass stream_select() unbegrenzt blockiert, bis ein Stream aktiv wird. Ein Timeout von 0 (und $microseconds = 0) führt zu einem sofortigen Poll ohne Wartezeit. Diese Funktion eignet sich besonders für Multiplexing von Socket-Verbindungen, Chat-Server, Proxys oder jede Situation, in der mehrere Datenquellen gleichzeitig bedient werden müssen.

Streams können mit stream_socket_client(), stream_socket_server(), fsockopen() oder fopen() erstellt werden. STDIN, STDOUT und STDERR können ebenfalls verwendet werden.

Parameter

Name Typ Default Beschreibung
$read Pflicht array Array von Streams, die auf Lesbarkeit überwacht werden sollen. Nach dem Aufruf enthält das Array nur noch die lesbaren Streams. Zum Ignorieren [] oder null übergeben.
$write Pflicht array|null Array von Streams, die auf Schreibbereitschaft überwacht werden sollen. Nach dem Aufruf enthält das Array nur noch die schreibbereiten Streams. Kann null sein, wenn Schreibbereitschaft nicht geprüft werden soll.
$except Pflicht array|null Array von Streams, die auf Ausnahmezustände (z. B. Out-of-band-Daten bei TCP-Sockets) überwacht werden sollen. In der Praxis selten benötigt; kann null sein.
$seconds Pflicht int|null Timeout-Sekunden. null bedeutet unbegrenztes Warten; 0 bedeutet sofortiger Poll (kein Warten). Muss zusammen mit $microseconds angegeben werden.
$microseconds int 0 Zusätzliche Mikrosekunden zum Timeout. Ermöglicht feinere Timeout-Auflösung unterhalb einer Sekunde.

Rückgabewert

Typ
int|false
Beschreibung
Gibt die Anzahl der Streams zurück, die nach dem Aufruf in den Arrays verblieben sind (also aktive Streams). Gibt 0 zurück, wenn der Timeout abgelaufen ist, ohne dass ein Stream aktiv wurde. Gibt false zurück bei einem Fehler (z. B. wenn alle drei Arrays leer oder null sind, oder bei einem Systemfehler).

Beispiele

Mehrere Sockets gleichzeitig auf eingehende Daten überwachen

<?php
// Zwei nicht-blockierende Verbindungen aufbauen
$sock1 = stream_socket_client('tcp://example.com:80', $errno1, $errstr1, 5);
$sock2 = stream_socket_client('tcp://example.org:80', $errno2, $errstr2, 5);

if (!$sock1 || !$sock2) {
    die('Verbindung fehlgeschlagen');
}

// HTTP-Anfragen absenden
fwrite($sock1, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n");
fwrite($sock2, "GET / HTTP/1.0\r\nHost: example.org\r\n\r\n");

$streams = [$sock1, $sock2];

while (!empty($streams)) {
    $read   = $streams;
    $write  = null;
    $except = null;

    // Bis zu 5 Sekunden auf Aktivität warten
    $ready = stream_select($read, $write, $except, 5);

    if ($ready === false) {
        echo "Fehler bei stream_select()\n";
        break;
    }

    if ($ready === 0) {
        echo "Timeout: Keine Antwort innerhalb von 5 Sekunden.\n";
        break;
    }

    // Nur aktive Streams verarbeiten
    foreach ($read as $stream) {
        $data = fread($stream, 1024);
        if ($data === '' || $data === false || feof($stream)) {
            // Stream ist geschlossen — aus Überwachungsliste entfernen
            $key = array_search($stream, $streams, true);
            if ($key !== false) {
                unset($streams[$key]);
            }
            fclose($stream);
        } else {
            echo "Daten empfangen (". strlen($data) ." Bytes)\n";
        }
    }
}
?>
Daten empfangen (1024 Bytes) Daten empfangen (1024 Bytes)

Nicht-blockierender Poll (sofortiger Timeout = 0)

<?php
// Stream öffnen (z. B. STDIN in einer CLI-Anwendung)
$read   = [STDIN];
$write  = null;
$except = null;

// Sofortige Prüfung ohne zu warten (timeout = 0)
$ready = stream_select($read, $write, $except, 0, 0);

if ($ready > 0) {
    $line = fgets(STDIN);
    echo 'Eingabe erkannt: ' . $line;
} else {
    echo "Keine Eingabe vorhanden (nicht blockierend).\n";
}
?>
Keine Eingabe vorhanden (nicht blockierend).

// Wichtig · Fallstricke

Wichtig: Alle drei Array-Parameter werden als Referenz übergeben und verändert. Wenn du die originalen Stream-Listen benötigst, musst du sie vor dem Aufruf kopieren (z. B. $read = $meineStreams;).

Signal-Unterbrechung: Unter Unix kann stream_select() durch ein Signal (z. B. SIGCHLD) unterbrochen werden und false zurückgeben, obwohl kein Fehler vorliegt. In solchen Fällen sollte false nicht als fataler Fehler behandelt werden, wenn stream_select() in einer Schleife läuft.

Windows-Einschränkung: Unter Windows können nur Sockets überwacht werden — reguläre Datei-Handles und Pipes funktionieren möglicherweise nicht korrekt mit stream_select().

Leere Arrays: Wenn alle drei Arrays leer oder null sind, gibt die Funktion false zurück und erzeugt eine Warnung. Mindestens ein Stream muss übergeben werden.