Wie man SIGPIPE verhindert (oder richtig behandelt)
Ich habe ein kleines server-Programm, das akzeptiert verbindungen über eine TCP-oder lokalen UNIX-socket, liest einen einfachen Befehl und, je nach Befehl sendet eine Antwort. Das problem ist, dass der Kunde kein Interesse an der Antwort manchmal und beendet früh, so zu schreiben, dass die Buchse bewirkt, dass ein SIGPIPE und mein server crash. Was ist die best practice, um zu verhindern, dass der Absturz hier? Gibt es eine Möglichkeit zu überprüfen, ob die andere Seite der Zeile ist noch nicht zu Ende gelesen? (wählen Sie() scheint nicht zu funktionieren hier, wie Sie das immer sagt der socket schreibbar ist). Oder sollte ich einfach nur fangen die SIGPIPE mit einem handler und es ignorieren?
InformationsquelleAutor der Frage jkramer | 2008-09-20
Du musst angemeldet sein, um einen Kommentar abzugeben.
Dass Sie in der Regel ignorieren die
SIGPIPE
und verarbeiten Sie den Fehler direkt im code. Dies ist, weil die signal-Handler in C haben viele Einschränkungen auf, was Sie tun können.Den meisten portablen Weg, dies zu tun ist, um die
SIGPIPE
handlerSIG_IGN
. Dies wird verhindern, dass ein socket oder eine pipe zu schreiben, verursacht einenSIGPIPE
signal.Ignorieren die
SIGPIPE
signal, verwenden Sie den folgenden code:Wenn Sie mit der
send()
anrufen, eine andere Möglichkeit ist die Verwendung desMSG_NOSIGNAL
option, die dieSIGPIPE
Verhalten aus-auf einer pro-call-basis. Beachten Sie, dass nicht alle Betriebssysteme unterstützen dieMSG_NOSIGNAL
Flagge.Schließlich, Sie möchten möglicherweise auch die
SO_SIGNOPIPE
socket-flag, das gesetzt werden kann, mitsetsockopt()
auf einigen Betriebssystemen. Dies wird verhindern, dassSIGPIPE
wird verursacht, indem Sie schreibt, nur um die buchsen, die es gesetzt ist.InformationsquelleAutor der Antwort dvorak
Andere Methode ist das ändern der Steckdose, so wird es nie SIGPIPE erzeugt, die auf write(). Das ist bequemer, in Bibliotheken, wo Sie nicht möchten, könnte eine Globale signal-handler für den SIGPIPE.
Auf den meisten BSD-basierten (MacOS, FreeBSD...) Systeme, (vorausgesetzt, Sie sind mit C/C++), kann man dies mit:
Mit diesem in der Wirkung, statt den SIGPIPE-signal wird generiert, EPIPE zurückgegeben werden.
InformationsquelleAutor der Antwort user55807
Ich bin super spät zur party, aber
SO_NOSIGPIPE
ist nicht tragbar, und möglicherweise nicht auf Ihrem system funktionieren (es scheint zu sein, ein BSD-Sache).Eine gute alternative, wenn Sie auf, sagen wir mal, ein Linux-system ohne
SO_NOSIGPIPE
wäre, um dieMSG_NOSIGNAL
Flagge auf Ihrem senden(2) - Aufruf.Beispiel ersetzen
write(...)
durchsend(...,MSG_NOSIGNAL)
(siehe nobar's Kommentar)InformationsquelleAutor der Antwort sklnd
In diesem post ich beschrieb mögliche Lösung für Solaris Fall, wenn weder SO_NOSIGPIPE noch MSG_NOSIGNAL verfügbar ist.
Beispiel-code bei https://github.com/kroki/XProbes/blob/1447f3d93b6dbf273919af15e59f35cca58fcc23/src/libxprobes.c#L156
InformationsquelleAutor der Antwort kroki
Handle SIGPIPE Lokal
Es ist normalerweise am besten, um den Fehler zu behandeln, die lokal anstatt in einer globalen signal-Ereignis-handler, da lokal haben Sie mehr Kontext zu dem, was Los ist und was den Rückgriff zu nehmen.
Ich habe einen Kommunikations-layer in einer meiner apps, die erlaubt, dass meine app zur Kommunikation mit einem externen Zubehör. Wenn eine write-Fehler tritt auf, I throw und Ausnahme in der Kommunikations-Schicht und lassen Sie es Blase bis zu einem try-catch-block zum verarbeiten es dort.
Code:
Den code zu ignorieren, ein SIGPIPE-signal, so dass Sie verarbeiten kann es lokal ist:
Dieser code wird verhindern, dass das SIGPIPE-signal ausgelöst wird, aber du erhältst eine lese - /schreib-Fehler, wenn versucht, den socket zu verwenden, so dass Sie brauchen, um zu überprüfen, dass.
InformationsquelleAutor der Antwort Sam
Können Sie nicht verhindern, dass der Prozess am anderen Ende des Rohres zu verlassen, und wenn es beendet, bevor Sie fertig sind zu schreiben, Sie erhalten ein SIGPIPE-signal. Wenn Sie SIG_IGN das signal, dann ist dein schreiben zurück mit einem Fehler - und Sie brauchen, um beachten und darauf zu reagieren, dass Fehler. Nur fangen und ignorieren das signal in ein hf ist keine gute Idee-man muss beachten, dass die Pfeife ist inzwischen geschlossen und das Programm verändern das Verhalten, damit es nicht schreiben, um das Rohr wieder (denn das signal wird erzeugt, die wieder und wieder ignoriert, und Sie werde versuchen Sie es erneut, und der gesamte Prozess könnte noch ein lange Zeit und verbrauchen sehr viel CPU-Leistung).
InformationsquelleAutor der Antwort Jonathan Leffler
Ich glaube, dass richtig ist. Sie möchten wissen, Wann Sie das andere Ende geschlossen hat, Ihre Beschreibung und das ist, was SIGPIPE sagt Sie.
Sam
InformationsquelleAutor der Antwort Sam Reynolds
Linux Handbuch sagte:
Aber für Ubuntu 12.04 ist es nicht Recht. Ich schrieb einen test für diesen Fall, und ich erhalten immer EPIPE withot SIGPIPE. SIGPIPE wird genereated wenn ich versuche zu schreiben, um die gleichen kaputten Buchse zweiten mal. So brauchen Sie nicht zu ignorieren, SIGPIPE, wenn dieses signal passiert, es heißt Logik-Fehler in Ihrem Programm.
InformationsquelleAutor der Antwort talash
Entweder deaktivieren sigpipes als pro jeder oder fangen und ignorieren Sie den Fehler.
Ja, verwenden Sie().
Müssen Sie auf die Lesen bits. Können Sie wahrscheinlich ignorieren die schreiben bits.
Wenn die Gegenseite schließt die Datei verarbeiten, wählen Sie wird Ihnen sagen, dass es ist, Daten bereit zu Lesen. Wenn Sie gehen und Lesen, dass Sie wieder 0 Byte, das ist wie das Betriebssystem Ihnen mitteilt, dass das Datei-handle geschlossen wurde.
Nur die Zeit, Sie können nicht ignorieren, das schreiben von bits ist, wenn Sie das senden von großen Mengen, und es ist ein Risiko, das andere Ende immer im Rückstand, die kann dazu führen, Ihre Puffer zu füllen. Wenn das passiert, dann versucht, zu schreiben, um die Datei-handle kann dazu führen, dass das Programm/thread zu sperren oder nicht. Testen wählen Sie vor dem schreiben schützen Sie, aber es gibt auch keine Garantie, dass das andere Ende gesund ist, oder dass Ihre Daten zu kommen.
Beachten Sie, dass Sie erhalten ein sigpipe von close(), sowie beim schreiben.
Schließen, spült jede gepufferte Daten. Wenn das andere Ende der bereits geschlossen wurde, schließen Sie dann fehl, und Sie erhalten ein sigpipe.
Wenn Sie mit gepufferten TCPIP, dann das erfolgreiche schreiben bedeutet einfach nur Ihre Daten in die Warteschlange eingereiht wurde, zu senden, es bedeutet nicht, dass es gesendet wurde. Bis Sie sich erfolgreich in der Nähe nennen, wissen Sie nicht, dass Ihre Daten gesendet wurden.
Sigpipe Ihnen sagt, etwas ist schief gegangen, es muss Ihnen nicht sagen, was oder was man dagegen machen sollte.
InformationsquelleAutor der Antwort Ben Aveling
Unter einem modernen POSIX-system (z.B. Linux), können Sie die
sigprocmask()
Funktion.Wenn Sie möchten, um den vorherigen Zustand wiederherzustellen später, stellen Sie sicher, speichern Sie die
old_state
irgendwo sicher. Wenn Sie rufen Sie die Funktion mehrfach auf, müssen Sie entweder einen Stapel oder nur speichern Sie die ersten oder letztenold_state
... oder vielleicht haben Sie eine Funktion, die entfernt ein bestimmtes signal blockiert.Für weitere Informationen Lesen Sie die Manpage.
InformationsquelleAutor der Antwort Alexis Wilke