Start · Sprachen · PHP · Referenz · socket_recvfrom

socket_recvfrom

Funktion

Empfängt Daten von einem Socket und liefert dabei – unabhängig vom Verbindungstyp – auch die Absenderadresse zurück.

seit PHP 4.1.0 Kategorie: http

Signatur

socket_recvfrom(Socket $socket, string &$buf, int $len, int $flags, string &$name, int &$port = null): int|false

Beschreibung

socket_recvfrom() liest bis zu $len Bytes vom angegebenen Socket in den Puffer $buf und speichert gleichzeitig die IP-Adresse (bzw. den Unix-Domain-Socket-Pfad) des Absenders in $name sowie bei UDP/IP den Absender-Port in $port. Dies macht die Funktion besonders nützlich für verbindungslose Protokolle wie UDP, wo jedes Datagramm potenziell von einem anderen Host stammen kann.

Im Gegensatz zu socket_recv() funktioniert socket_recvfrom() auch ohne eine zuvor aufgebaute Verbindung (socket_connect()). Dadurch eignet sie sich ideal für UDP-Server, die Anfragen von beliebigen Clients empfangen und gezielt antworten müssen, ohne eine dauerhafte Verbindung aufrechtzuerhalten.

Der Parameter $flags erlaubt es, das Empfangsverhalten zu steuern. Gängige Werte sind MSG_WAITALL (warte bis alle Bytes angekommen sind), MSG_PEEK (Daten lesen ohne sie aus dem Puffer zu entfernen) und MSG_DONTWAIT (nicht blockierender Empfang). Diese Flags können mit dem bitweisen ODER-Operator kombiniert werden.

Schlägt der Empfang fehl, gibt die Funktion false zurück. Mit socket_last_error() und socket_strerror() lässt sich der genaue Fehlergrund ermitteln. Bei Erfolg wird die Anzahl der tatsächlich empfangenen Bytes zurückgegeben.

Parameter

Name Typ Default Beschreibung
$socket Pflicht Socket Eine gültige Socket-Ressource bzw. ein Socket-Objekt, das zuvor mit socket_create() erzeugt wurde.
$buf Pflicht string Referenz auf eine Variable, in die die empfangenen Daten geschrieben werden.
$len Pflicht int Maximale Anzahl an Bytes, die empfangen werden sollen. Bei UDP sollte dieser Wert die maximale Datagrammgröße nicht überschreiten (typisch: 65535 Bytes).
$flags Pflicht int Bitmaske aus Empfangs-Flags wie MSG_WAITALL, MSG_PEEK oder MSG_DONTWAIT. Übergib 0 für Standardverhalten.
$name Pflicht string Referenz auf eine Variable, die nach dem Aufruf die IP-Adresse (IPv4/IPv6) oder den Pfad (Unix-Domain-Socket) des Absenders enthält.
$port int null Referenz auf eine Variable, die den Absender-Port enthält. Nur bei AF_INET- und AF_INET6-Sockets relevant; bei Unix-Domain-Sockets wird dieser Parameter ignoriert.

Rückgabewert

Typ
int|false
Beschreibung
Gibt die Anzahl der empfangenen Bytes als int zurück. Bei einem Fehler wird false zurückgegeben; der genaue Fehler kann mit socket_last_error() abgefragt werden.

Beispiele

Einfacher UDP-Server: Datagramme empfangen und Absender ermitteln

<?php
// UDP-Socket erstellen und an Port 9000 binden
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
if ($socket === false) {
    die('socket_create() fehlgeschlagen: ' . socket_strerror(socket_last_error()));
}

if (!socket_bind($socket, '0.0.0.0', 9000)) {
    die('socket_bind() fehlgeschlagen: ' . socket_strerror(socket_last_error($socket)));
}

echo "UDP-Server lauscht auf Port 9000 ...\n";

// Auf eingehende Datagramme warten
$buf  = '';
$from = '';
$port = 0;

$bytes = socket_recvfrom($socket, $buf, 65535, 0, $from, $port);

if ($bytes === false) {
    echo 'Fehler: ' . socket_strerror(socket_last_error($socket)) . "\n";
} else {
    echo "Empfangen: {$bytes} Byte(s) von {$from}:{$port}\n";
    echo "Inhalt: {$buf}\n";

    // Antwort an den Absender schicken
    socket_sendto($socket, 'ACK', 3, 0, $from, $port);
}

socket_close($socket);
UDP-Server lauscht auf Port 9000 ... Empfangen: 5 Byte(s) von 127.0.0.1:54321 Inhalt: Hallo

UDP-Server-Schleife: Mehrere Clients bedienen

<?php
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($socket, '0.0.0.0', 9001);

echo "Warte auf UDP-Pakete auf Port 9001 ...\n";

while (true) {
    $buf  = '';
    $from = '';
    $port = 0;

    $bytes = socket_recvfrom($socket, $buf, 4096, 0, $from, $port);

    if ($bytes === false) {
        $errCode = socket_last_error($socket);
        echo 'Fehler ' . $errCode . ': ' . socket_strerror($errCode) . "\n";
        continue;
    }

    $ts  = date('H:i:s');
    $msg = trim($buf);
    echo "[{$ts}] {$from}:{$port} → {$msg}\n";

    // Echo zurücksenden
    $response = strtoupper($msg);
    socket_sendto($socket, $response, strlen($response), 0, $from, $port);

    if ($msg === 'QUIT') {
        echo "Server wird beendet.\n";
        break;
    }
}

socket_close($socket);
[12:00:01] 192.168.1.10:50234 → ping [12:00:05] 192.168.1.20:50400 → QUIT Server wird beendet.

// Wichtig · Fallstricke

Sicherheit: Die empfangenen Daten in $buf stammen aus einer nicht vertrauenswürdigen Quelle. Validiere und sanitisiere den Inhalt immer, bevor er weiterverarbeitet oder ausgegeben wird, um Buffer-Overflows in nachgelagerten Funktionen oder XSS-Angriffe zu vermeiden.

Blockierendes Verhalten: Standardmäßig blockiert socket_recvfrom(), bis Daten eintreffen. Mit socket_set_nonblock() oder dem Flag MSG_DONTWAIT kann der Socket auf nicht-blockierenden Modus umgestellt werden – in diesem Fall gibt die Funktion sofort false zurück, wenn keine Daten vorliegen (Fehlercode EAGAIN/EWOULDBLOCK).

IPv6: Bei AF_INET6-Sockets enthält $name die IPv6-Adresse im Standardformat, z. B. ::1. $port wird analog zu IPv4 befüllt.

PHP 8.0+: Ab PHP 8.0 ist $socket ein Socket-Objekt statt einer Ressource. Der Funktionsaufruf selbst bleibt kompatibel.