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.
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)
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:
socket_close () nicht ausgeführt : Die Verbindung ist nicht geschlossen, die Systemressourcen werden nicht veröffentlicht.
Das Skript verlässt abnormal : Die erstellte Verbindung wird nicht gereinigt und hinterlässt einen Zombie -Sockel.
Signal -Interrupt (wie Strg+C): Es wird keine Folgen verarbeitet.
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.
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);
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.
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:
Sockel initialisieren
Setzen Sie nicht blockierende/auswählen
Empfangen Sie eine Verbindung in der Hauptschleife und Prozessanfragen
Erfassen Sie das Terminierungssignal und beenden Sie die Schleife
Reinigen Sie alle offenen Verbindungen
Schließen Sie schließlich die Hörstecke
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";
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.