Start · Sprachen · PHP · Referenz · socket_set_nonblock

socket_set_nonblock

Funktion

Setzt einen Socket in den nicht-blockierenden (non-blocking) Modus, sodass Socket-Operationen sofort zurückkehren, auch wenn sie noch nicht abgeschlossen sind.

seit PHP 4.1.0 Kategorie: http

Signatur

socket_set_nonblock(Socket $socket): bool

Beschreibung

socket_set_nonblock() versetzt den übergebenen Socket in den nicht-blockierenden Modus. Im Gegensatz zum Standard-Blocking-Modus, bei dem Funktionen wie socket_read() oder socket_accept() so lange warten, bis Daten verfügbar sind, kehren diese Funktionen im Non-Blocking-Modus sofort zurück – entweder mit Daten oder mit einem Fehlercode (SOCKET_EAGAIN / SOCKET_EWOULDBLOCK), wenn keine Daten verfügbar sind.

Dieser Modus ist besonders nützlich beim Aufbau von Server-Anwendungen, die mehrere Verbindungen gleichzeitig verwalten müssen, ohne für jeden Client einen eigenen Prozess oder Thread zu benötigen. Typischerweise wird er in Kombination mit socket_select() eingesetzt, um effizient auf mehrere Sockets zu warten.

Das Gegenstück ist socket_set_block(), das den Socket wieder in den blockierenden Modus zurückversetzt. Es empfiehlt sich, den Modus bewusst zu wählen und Fehler (SOCKET_EAGAIN) korrekt zu behandeln, da sie im Non-Blocking-Modus kein eigentlicher Fehler, sondern ein normaler Betriebszustand sind.

Parameter

Name Typ Default Beschreibung
$socket Pflicht Socket Eine gültige Socket-Instanz, die zuvor mit socket_create() oder socket_accept() erzeugt wurde.

Rückgabewert

Typ
bool
Beschreibung
Gibt true bei Erfolg zurück. Im Fehlerfall wird false zurückgegeben; der genaue Fehlercode kann dann mit socket_last_error() abgerufen werden.

Beispiele

Einfacher Non-Blocking-Server mit socket_select()

<?php
// Socket erstellen
$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($server === false) {
    die('socket_create() fehlgeschlagen: ' . socket_strerror(socket_last_error()));
}

// Socket an Port binden
socket_bind($server, '0.0.0.0', 8080);
socket_listen($server, 5);

// In Non-Blocking-Modus wechseln
if (!socket_set_nonblock($server)) {
    die('socket_set_nonblock() fehlgeschlagen: ' . socket_strerror(socket_last_error($server)));
}

$clients = [];

echo "Server läuft im Non-Blocking-Modus auf Port 8080...\n";

for ($i = 0; $i < 10; $i++) {
    // Neue Verbindung akzeptieren – kehrt sofort zurück (non-blocking)
    $client = @socket_accept($server);
    if ($client !== false) {
        socket_set_nonblock($client);
        $clients[] = $client;
        echo "Neuer Client verbunden.\n";
    }

    // Vorhandene Clients abfragen
    foreach ($clients as $key => $c) {
        $data = @socket_read($c, 1024);
        if ($data === false) {
            // EAGAIN: Keine Daten verfügbar – kein Fehler im Non-Blocking-Modus
            $errno = socket_last_error($c);
            if ($errno !== SOCKET_EAGAIN && $errno !== SOCKET_EWOULDBLOCK) {
                echo "Fehler bei Client: " . socket_strerror($errno) . "\n";
                socket_close($c);
                unset($clients[$key]);
            }
        } elseif ($data === '') {
            // Verbindung geschlossen
            socket_close($c);
            unset($clients[$key]);
        } else {
            echo "Empfangen: $data\n";
            socket_write($c, "Echo: $data");
        }
    }

    usleep(100000); // 100 ms warten
}

socket_close($server);
Server läuft im Non-Blocking-Modus auf Port 8080...

Non-Blocking-Modus und anschließende Rückkehr zu Blocking

<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, 'example.com', 80);

// Auf Non-Blocking umschalten
socket_set_nonblock($socket);

$result = @socket_read($socket, 512);
if ($result === false) {
    $errno = socket_last_error($socket);
    if ($errno === SOCKET_EAGAIN || $errno === SOCKET_EWOULDBLOCK) {
        echo "Keine Daten verfügbar (Non-Blocking, kein Fehler).\n";
    } else {
        echo "Fehler: " . socket_strerror($errno) . "\n";
    }
}

// Zurück in den Blocking-Modus
socket_set_block($socket);

$request = "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n";
socket_write($socket, $request);
$response = socket_read($socket, 2048);
echo substr($response, 0, 100) . "\n";

socket_close($socket);
Keine Daten verfügbar (Non-Blocking, kein Fehler).

// Wichtig · Fallstricke

Fehlerbehandlung: Im Non-Blocking-Modus liefern socket_read(), socket_accept() und ähnliche Funktionen false zurück, wenn gerade keine Daten verfügbar sind. Das ist kein Fehler – der Fehlercode ist dann SOCKET_EAGAIN oder SOCKET_EWOULDBLOCK. Diese Codes müssen explizit abgefangen werden, um echte Fehler von "keine Daten verfügbar" zu unterscheiden.

Kompatibilität: Ab PHP 8.0 erwartet die Funktion ein Socket-Objekt statt einer Ressource. In älteren PHP-Versionen wurde eine resource übergeben.

Empfehlung: Für komplexe Event-gesteuerte Netzwerkanwendungen empfehlen sich Bibliotheken wie ReactPHP oder Swoole, die intern ebenfalls auf Non-Blocking-Sockets aufbauen und eine abstraktere API bieten.