Aktueller Standort: Startseite> Neueste Artikel> Wie man eine von Socket_accept () empfangene Verbindung elegant schließt ()

Wie man eine von Socket_accept () empfangene Verbindung elegant schließt ()

M66 2025-05-19

Beim Erstellen einer Socket-basierten Serveranwendung mit PHP ist Socket_accept () eine der Kernfunktionen, die Verbindungsanforderungen vom Client akzeptiert. Wenn das Verbindungsmanagement jedoch nicht ordnungsgemäß behandelt wird, ist es einfach, Ressourcenleckage und sogar abnormale Service -Kündigung zu verursachen. In diesem Artikel wird untersucht, wie diese Verbindungen hergestellt werden können, um sicherzustellen, dass Ressourcen rechtzeitig freigegeben werden können und die Stabilität und Zuverlässigkeit von Diensten aufrechterhalten werden.

1. grundlegende Verwendung von Socket_accept ()

Sehen Sie sich vor dem Verständnis der eleganten Abschaltung ein Basic -Socket -Server -Beispiel an:

 $address = '0.0.0.0';
$port = 12345;

$serverSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($serverSocket, $address, $port);
socket_listen($serverSocket);

while (true) {
    $clientSocket = socket_accept($serverSocket);
    // Einfache Antwort
    socket_write($clientSocket, "Hello client!\n");
    socket_close($clientSocket);
}

In diesem Beispiel wird der Server weiter ausgeführt, die Verbindung empfängt und antwortet. Obwohl der Code ausgeführt werden kann, treten die folgenden Probleme auf, wenn die Verbindung geschlossen wird und die Ausnahme bei hoher Parallelität oder langfristigem Laufen unangemessen behandelt wird:

  • Dateideskriptorleck (Überschreitungen der Systemressourcengrenzen)

  • Die Verbindung ist nicht geschlossen, wodurch Time_wait ansammelt

  • Der Prozess ist gezwungen, zu enden (falls er auf Sigint gestoßen ist)

2. Analyse der Grundursache des Problems

PHPs Socket_accept () ist eine Blockierungsfunktion , was bedeutet, dass es auf keine Verbindungsanforderung wartet. Dieses Verhalten verhindert das normale Abschalten des Prozesses beim Verlassen des Dienstes, des Neustarts oder der Beendet. Wenn die Ressource nicht korrekt veröffentlicht wird, kann dies zu:

  1. socket_close () nicht ausgeführt : Die Verbindung ist nicht geschlossen, die Systemressourcen werden nicht veröffentlicht.

  2. Das Skript verlässt abnormal : Die erstellte Verbindung wird nicht gereinigt und hinterlässt einen Zombie -Sockel.

  3. Signal -Interrupt (wie Strg+C): Es wird keine Folgen verarbeitet.

3.. Schlüsseltechnologien zum Erreichen eleganter Schließung

1. Verwenden Sie stream_socket_server () anstelle von socket_create ()

Obwohl die Socket_* -Serie eine Steuerung unteren liefert, ist das Stream_Socket_Server () von PHP einfacher zu implementieren und das nicht blockierende Verhalten zu implementieren, um den Code zu vereinfachen.

Wenn Sie jedoch auf Socket_* bestehen, können die folgenden Methoden auch einen eleganten Verschluss erreichen.

2. Setzen Sie den Nicht-Blocking-Modus + Signalüberwachung

Socket_set_nonblock () kann von blockiert socket_accept () vermieden werden:

 socket_set_nonblock($serverSocket);

Auf diese Weise können wir eine Schleife verwenden, um zu prüfen, ob eine Verbindung besteht, und auf das Terminierungssignal zuhören:

 declare(ticks = 1);

$running = true;

pcntl_signal(SIGINT, function() use (&$running) {
    echo "erfassen SIGINT,Bereiten Sie sich auf den Ausgang vor...\n";
    $running = false;
});

while ($running) {
    $clientSocket = @socket_accept($serverSocket);
    if ($clientSocket !== false) {
        socket_write($clientSocket, "Hello client!\n");
        socket_close($clientSocket);
    } else {
        usleep(100000); // vermeiden CPU Zu hohe Belegung
    }
}

socket_close($serverSocket);

3.. Verwenden Sie SELECT, um Ereignisschleifen zu simulieren

Wenn Sie mehrere Sockets anhören müssen, können Sie Socket_Select () kombinieren, um das ereignisgesteuerte Modell zu implementieren:

 $readSockets = [$serverSocket];
$write = $except = null;

if (socket_select($readSockets, $write, $except, 1) > 0) {
    foreach ($readSockets as $sock) {
        if ($sock === $serverSocket) {
            $clientSocket = socket_accept($serverSocket);
            if ($clientSocket !== false) {
                socket_write($clientSocket, "Hi\n");
                socket_close($clientSocket);
            }
        }
    }
}

Socket_Select () kann eine Zeitüberschreitung rechtzeitig einstellen oder auf Interrupt -Signale reagieren, die für die Implementierung robusterer Serverprogramme geeignet sind.

4. Vorschläge zur Ressourcenreinigung

Stellen Sie sicher, dass jede von socket_create () und socket_accept () erhaltene Ressource gepaart und ausgeführt wird socket_close () . Ein gut strukturierter Lebenszyklus für das Lebenszyklus von Socket ist wie folgt:

  1. Sockel initialisieren

  2. Setzen Sie nicht blockierende/auswählen

  3. Empfangen Sie eine Verbindung in der Hauptschleife und Prozessanfragen

  4. Erfassen Sie das Terminierungssignal und beenden Sie die Schleife

  5. Reinigen Sie alle offenen Verbindungen

  6. Schließen Sie schließlich die Hörstecke

V. Vollständiges Beispiel

Hier finden Sie ein vollständiges Beispiel, das Signalerfassung, nicht blockierende Modus und Ressourcenreinigung implementiert:

 declare(ticks = 1);

$serverSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($serverSocket, '0.0.0.0', 8000);
socket_listen($serverSocket);
socket_set_nonblock($serverSocket);

$running = true;

pcntl_signal(SIGINT, function() use (&$running) {
    echo "Erhielt ein Kündigungssignal,Bereiten Sie sich darauf vor, den Service zu schließen...\n";
    $running = false;
});

while ($running) {
    $clientSocket = @socket_accept($serverSocket);
    if ($clientSocket) {
        socket_write($clientSocket, "Willkommen zu Besuch m66.net!\n");
        socket_close($clientSocket);
    } else {
        usleep(100000);
    }
}

socket_close($serverSocket);
echo "Der Service wurde elegant geschlossen。\n";

6. Zusammenfassung

Obwohl die von PHP bereitgestellte Socket -Programmierschnittstelle leistungsfähig ist, bringt sie auch die Komplexität des Ressourcenmanagements. Durch das Festlegen des Nicht-Blocking-Modus, das Anhören von Terminationssignalen, mithilfe von Socket_Select () und anderen Methoden kann "elegantes Abschalten" bei PHP erreicht werden, wodurch die Probleme der Ressourcenleckage und abnormaler Kündigung effektiv vermieden werden. Diese Methoden sind besonders wichtig, um langjährige Dienste zu erstellen.

Denken Sie daran: Veröffentlichen Sie immer jede von Ihnen geöffnete Ressource, einschließlich Sockets.