Start · Sprachen · PHP · Referenz · socket_recvmsg

socket_recvmsg

Funktion

Liest eine Nachricht von einem Socket und befüllt ein assoziatives Array mit Nachrichtendaten, Absenderadresse und Hilfsdaten (ancillary data).

seit PHP 5.5.0 Kategorie: http

Signatur

socket_recvmsg(Socket $socket, array &$message, int $flags = 0): int|false

Beschreibung

socket_recvmsg() ist die PHP-Entsprechung des POSIX-Systemaufrufs recvmsg(2). Sie liest eine vollständige Nachricht von einem Socket und gibt neben dem eigentlichen Nutzdaten-Puffer auch Metainformationen wie die Absenderadresse und sogenannte Ancillary-Data (z. B. übergebene Dateideskriptoren oder Credentials) zurück. Das Ergebnis wird direkt in das per Referenz übergebene $message-Array geschrieben.

Die Funktion eignet sich besonders für Unix-Domain-Sockets, wenn File-Descriptor-Passing oder Prozess-Authentifizierung (SCM_CREDENTIALS) benötigt wird, sowie für UDP-Sockets, bei denen pro Empfangsaufruf genau eine Datagramm-Einheit verarbeitet werden soll. Im Gegensatz zu socket_recv() liefert socket_recvmsg() strukturierte Steuerinformationen.

Das $message-Array muss vor dem Aufruf mit den Schlüsseln name (Puffer für die Absenderadresse), iov (Array von I/O-Vektoren als Empfangspuffer) und optional control (Puffer für Ancillary-Data) vorbefüllt werden. Nach dem Aufruf enthält es die empfangenen Daten, die tatsächliche Absenderadresse und alle Steuernachrichten.

Die Funktion ist Teil der Socket-Erweiterung und steht nur auf Plattformen zur Verfügung, die recvmsg(2) unterstützen (Linux, macOS, BSD). Unter Windows ist sie nicht verfügbar.

Parameter

Name Typ Default Beschreibung
$socket Pflicht Socket Ein gültiges Socket-Objekt, das zuvor mit socket_create() erzeugt und mit einem lokalen Endpunkt verbunden wurde.
$message Pflicht array Wird per Referenz übergeben. Muss vor dem Aufruf initialisiert sein, z. B. mit ['name' => [], 'iov' => [''], 'control' => '']. Nach dem Aufruf enthält es die Schlüssel name (Absenderadresse), iov (Empfangspuffer-Array), control (Steuernachrichten) und flags (Nachrichten-Flags).
$flags int 0 Bitmaske aus Empfangs-Flags, z. B. MSG_WAITALL, MSG_PEEK oder MSG_DONTWAIT. Wird als zweites Argument an recvmsg(2) weitergegeben.

Rückgabewert

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

Beispiele

Einfacher UDP-Empfang mit socket_recvmsg()

<?php
// Server-Seite: UDP-Socket erstellen und binden
$server = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($server, '127.0.0.1', 9000);

// Nachrichtenstruktur vorbereiten
$message = [
    'name'    => [],          // Absenderadresse wird hier eingetragen
    'iov'     => [str_repeat('\0', 1024)], // Empfangspuffer (1 KB)
    'control' => '',          // Ancillary-Data-Puffer (hier leer)
];

echo "Warte auf UDP-Paket...\n";
$bytes = socket_recvmsg($server, $message, 0);

if ($bytes === false) {
    echo 'Fehler: ' . socket_strerror(socket_last_error($server)) . "\n";
} else {
    $absender = $message['name'];
    $daten    = $message['iov'][0];
    echo "Empfangen ($bytes Byte) von {$absender['addr']}:{$absender['port']}\n";
    echo 'Inhalt: ' . substr($daten, 0, $bytes) . "\n";
}

socket_close($server);
Warte auf UDP-Paket... Empfangen (13 Byte) von 127.0.0.1:54321 Inhalt: Hello, Server!

File-Descriptor-Passing über Unix-Domain-Socket

<?php
// Empfänger-Seite: Unix-Domain-Socket, der einen Dateideskriptor entgegennimmt
$sock = socket_create(AF_UNIX, SOCK_STREAM, 0);
@unlink('/tmp/fd_pass.sock');
socket_bind($sock, '/tmp/fd_pass.sock');
socket_listen($sock);

$client = socket_accept($sock);

$message = [
    'name'    => [],
    'iov'     => [str_repeat('\0', 256)],
    // Ausreichend Puffer für SCM_RIGHTS Ancillary-Data reservieren
    'control' => str_repeat('\0', 1024),
];

$bytes = socket_recvmsg($client, $message, 0);

if ($bytes !== false) {
    echo 'Nutzdaten: ' . substr($message['iov'][0], 0, $bytes) . "\n";
    // Steuernachrichten (z. B. übergebene FDs) auswerten
    foreach ($message['control'] as $ctrl) {
        if ($ctrl['level'] === SOL_SOCKET && $ctrl['type'] === SCM_RIGHTS) {
            echo 'Empfangene Dateideskriptoren: ';
            echo implode(', ', $ctrl['data']) . "\n";
        }
    }
}

socket_close($client);
socket_close($sock);
unlink('/tmp/fd_pass.sock');
Nutzdaten: FD übergeben Empfangene Dateideskriptoren: 5

// Wichtig · Fallstricke

Plattformverfügbarkeit: socket_recvmsg() ist nur auf POSIX-Systemen (Linux, macOS, BSD) verfügbar. Unter Windows existiert die Funktion nicht, da recvmsg(2) dort nicht implementiert ist.

Puffergröße: Der iov-Eintrag im $message-Array muss mit einem ausreichend großen String vorinitialisiert werden (str_repeat('\0', N)). Ist der Puffer zu klein, werden empfangene Daten stillschweigend abgeschnitten und das Flag MSG_TRUNC gesetzt.

Sicherheit bei Ancillary-Data: Beim Empfang von Dateideskriptoren via SCM_RIGHTS müssen die empfangenen FDs nach Verwendung explizit mit fclose() bzw. den entsprechenden Socket-Funktionen geschlossen werden, da sie sonst als Dateileck bestehen bleiben.

Fehlerbehandlung: Im Fehlerfall gibt die Funktion false zurück. Der genaue Fehler sollte immer mit socket_last_error($socket) und socket_strerror() ausgelesen werden, da typische Fehler wie EAGAIN (kein Daten vorhanden bei nicht-blockierendem Socket) von echten Fehlern unterschieden werden müssen.