Wie kann ich wake wählen Sie() auf eine Steckdose in der Nähe?
Ich bin derzeit mit select-Schleife zu verwalten sockets in einem proxy. Eine der Anforderungen, die von diesem proxy ist, dass, wenn der proxy sendet eine Nachricht an die externe server und nicht bekommen, eine Antwort in einer bestimmten Zeit, der proxy sollte in der Nähe, die Buchse und versuchen, eine Verbindung zu einem sekundären server. Das schließen geschieht in einem eigenen thread, während die select-thread blockiert wartet auf Aktivität.
Ich habe ein Problem, herauszufinden, wie um zu erkennen, dass das socket geschlossen ist konkret, damit kann ich mit dem Fehler. Wenn ich den Aufruf von close() in den anderen thread, bekomme ich eine EBADF, aber ich kann nicht sagen, welcher socket geschlossen. Ich versuchte zu erkennen, die Buchse durch die Ausnahme fdset, dachte, es würde enthalten die geschlossene Buchse, aber ich bin nicht immer etwas zurückgekehrt. Ich habe auch gehört, dass der Aufruf von shutdown() sendet ein FIN auf dem server und erhalten eine FLOSSE zurück, so dass ich es schließen können; aber der springende Punkt ist, dass ich versuchen könnte, um diese zu schließen als Folge nicht bekommen, eine Antwort innerhalb der timeout-Zeit, so kann ich nicht tun, entweder.
Wenn meine Annahmen hier falsch sind, lass es mich wissen. Irgendwelche Ideen würde geschätzt.
BEARBEITEN:
In Reaktion auf die Vorschläge über die Verwendung von select time-out: ich muss die Schließung asynchron, da der client die Verbindung zu den proxy mal aus und ich kann nicht warten, um für die select-abgefragt werden. Dies würde nur funktionieren, wenn ich die Auswahl sehr klein, das würde dann ständig abrufen und verschwenden Ressourcen, die ich nicht will.
- Siehe auch stackoverflow.com/questions/543541/...
- Mögliche Duplikate von ausbrechen aus der Buchse auswählen
Du musst angemeldet sein, um einen Kommentar abzugeben.
In der Regel ich nur daneben die Buchse für das schließen in dem anderen thread, und dann, wenn select() kehrt aus der Aktivität oder timeout, führe ich ein cleanup-pass und schließen Sie alle Toten verbindungen und aktualisieren Sie die fd_set. Tun es auf eine andere Weise öffnet Sie bis zu Wettlaufsituationen, in denen Sie gab, bis auf die Verbindung, einfach als select() erkannte schließlich einige Daten für Sie, dann schließen Sie es, aber der andere thread versucht, die Daten zu verarbeiten, wurde entdeckt und verärgert zu finden, die Verbindung geschlossen.
Oh, und poll() ist in der Regel besser als select() in Bezug auf die nicht mit zu kopieren so viele Daten um.
Nicht befreien kann eine Ressource in einem thread, während ein anderer thread oder vielleicht verwenden werden. Aufruf
close
auf einem sockel, die vielleicht in einem anderen thread wird nie richtig funktionieren. Es wird immer potenziell katastrophalen race conditions.Gibt es zwei gute Lösungen für dein problem:
Den thread aufruft
select
verwenden Sie immer einen timeout, der nicht größer ist als die längste, die Sie bereit sind zu warten, um Prozess ein timeout. Wenn ein timeout Auftritt, zeigen, dass einige Stelle, die der thread aufruftselect
feststellen wird, wenn er zurückkehrt vonselect
. Habe diesen thread die eigentlicheclose
von der Buchse in-zwischen den anrufen zuselect
.Den thread erkennt, dass der timeout Aufruf
shutdown
auf den sockel. Dadurch wirdselect
zurück und haben dann in diesem thread tun, derclose
.Umgang mit EBADF auf select():
Dieser code setzt Voraus, Sie haben ein array von client-Strukturen, die "fd" - Mitglieder für den socket-Deskriptor. Die fcntl () - Aufruf wird überprüft, ob der socket noch "am Leben", und wenn nicht, tun wir, was wir haben, um zu entfernen die abgestorbenen Buchse und Ihre zugehörigen client-info.
Es ist schwer zu kommentieren, wenn man nur einen kleinen Teil des Elefanten, aber vielleicht sind Sie über die Dinge komplizieren?
Vermutlich haben Sie eine gewisse Struktur zu halten Spur von jeder Steckdose und seine Infos (wie die Zeit eine Antwort erhalten). Sie können ändern Sie die select () - Schleife verwenden einen timeout. Innerhalb es zu prüfen, ob es Zeit zum schließen des Sockets. Tun, was Sie tun müssen, für die enge und nicht hinzufügen, um den fd-sets das nächste mal um.
Wenn Sie mit poll(2) wie bereits in anderen Antworten, die Sie verwenden können, die POLLNVAL status, die im wesentlichen EBADF, aber auf einer pro-Datei-Deskriptor-basis, nicht auf das ganze system nennen, da es für select(2).
Verwenden Sie ein timeout für die wählen, und wenn der lese-bereit - /schreib-bereit/hatte-error-Sequenzen, die alle leer sind (w.r.t, sockel) überprüfen Sie, ob es geschlossen wurde.
Führen Sie einfach einen "test auswählen" auf jede einzelne Steckdose, die möglicherweise geschlossen haben mit einer null-timeout und überprüfen Sie die select-Ergebnis und errno, bis Sie einen gefunden, der hat geschlossen.
Folgende Stück der demo-code beginnt mit zwei server-sockets in separaten threads und erstellt zwei client-sockets eine Verbindung zum server-socket. Dann beginnt es einen anderen thread, der zufällig töten, einer der client-sockets, die nach 10 Sekunden (es wird nur schließen). Schließen Sie entweder client-socket-Ursachen, wählen Sie Fehler in der main-thread und den folgenden code wird nun testen, welche der beiden buchsen hat tatsächlich geschlossen.
Beispiel-Ausgabe für die Durchführung dieses test-code doppelt:
Jedoch, wenn Ihr system unterstützt
poll()
würde ich raten Ihnen dringend zu prüfen, die diese API nutzen, stattselect()
. Wählen ist ein ziemlich hässlich, legacy-API aus der Vergangenheit, nur bleibt es für die Abwärtskompatibilität mit vorhandenen code. Poll hat eine viel bessere Oberfläche für diese Aufgabe und es hat ein extra-flag direkt zu signalisieren, dass Sie ein socket geschlossen lokal:POLLNVAL
nachrevents
wenn das socket geschlossen wurde, unabhängig davon, welche flags du gebeten, auf Veranstaltungen, daPOLLNVAL
ist ein Ausgang nur die Flaggen, das heißt, es wird ignoriert, wenn festgelegt wird, aufevents
. Wenn der socket nicht geschlossen wurde lokal, sondern remote-server hat nur die Verbindung geschlossen, die fahnePOLLHUP
wird imrevents
(auch eine output-only-flag). Ein weiterer Vorteil der Befragung ist, dass das timeout einfach einen int-Wert (Millisekunden, feinkörnigen genug für echte Netzwerk-sockets) und dass es keine Beschränkungen für die Anzahl der sockets, die überwacht werden können oder deren numerischen Wertebereich.socket
nach derclose
aber bevor Sie rufenselect
bekommen und der gleiche Deskriptor.socket
sieht dein code bricht, wenn jemand upgrades, die Bibliothek.