Wie kann man SIGPIPE verhindern oder verhindern, dass der Server beendet wird?

Lesezeit: 4 Minuten

Benutzeravatar von towi
towi

Ein ganz normales C++-TCP-Serverprogramm, das verwendet wird pthreads, binden, Hören und annehmen. Ich habe das Szenario, dass die Server endet (sprich: stürzt ab), wenn ich einen verbundenen Client beende.

Der Grund für den Absturz ist, dass die write() rufen Sie an Datei schlägt fehl, daher erhält das Programm ein SIGPIPE. Und ich schätze, dadurch wird der Server beendet.

Ich dachte, “natürlich bedeutet unbehandeltes Signal Ausgang”, also lasst uns verwenden signal():

signal(SIGPIPE, SIG_IGN);

weil, genommen von man 2 write:

EPIPE fd an ein Rohr oder eine Muffe angeschlossen ist, deren lesendes Ende geschlossen ist. Wenn dies geschieht, erhält der Schreibvorgang auch ein SIGPIPE-Signal. (Daher wird der Write-Rückgabewert nur gesehen, wenn das Programm dieses Signal abfängt, blockiert oder ignoriert.)

Leider nein. Weder im Server-Thread noch in den Client-Threads scheint dies zu helfen.

So, wie verhindere ich das write() Anruf davon abhält, dieses Signal auszulösen, oder (um pragmatisch zu sein) wie verhindere ich, dass der Server beendet wird.


Meine Diagnosen sind:

  • Server-Thread gestartet, Bindung, Überwachung, Annahme.
  • Lassen Sie einen Client eine Verbindung herstellen (z. B. über Telnet)
  • Sende ein pkill telnet den Client zum Absturz bringen

unerwünschtes Verhalten: Server beendet, in gdb mit

... in write () at ../sysdeps/unix/syscall-template.S:82
82      T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)

und die zurückverfolgen:

#0  ... in write () at ../sysdeps/unix/syscall-template.S:82
#1  ... in ClientHandler::mesg(std::string) ()
#2  ... in ClientHandler::handle() ()
#3  ... in start_thread (arg=<value optimized out>) at pthread_create.c:300
#4  ... in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
#5  ... in ?? ()

  • Ich vermute hier, aber vielleicht müssen Sie den Dateideskriptor/Socket mit dem O_NOCTTY-Flag erstellen?

    – Vinicius Kamakura

    25. Juli 2011 um 20:20 Uhr

  • @hexa: Es ist unwahrscheinlich, dass O_NOCTTY etwas damit zu tun hat.

    – Jonathan Leffler

    25. Juli 2011 um 20:56 Uhr

  • Signal (SIGPIPE, SIG_IGN) ist das, was Sie wollen. Die eigentliche Frage ist, warum es bei dir nicht funktioniert. Vielleicht kehrt ein anderer Code seine Wirkung um, indem er einen separaten Signalhandler installiert? Oder ist es vielleicht nur so, dass Ihre Argumente für write() falsch sind und einen guten altmodischen Absturz verursachen (nicht im Zusammenhang mit SIGPIPE)?

    – Jeremy Friesner

    25. Juli 2011 um 21:59 Uhr

  • @Jeremy: Kein anderer Signalhandler, nur a select(). Und ich werde den Write-Call() dbl-checken.

    – towi

    26. Juli 2011 um 6:43 Uhr

  • @JeremyFriesner: Manpage für signal() sagt, dass “die Wirkung von signal() in einem Multithread-Prozess sind unspezifiziert” und empfiehlt die Verwendung sigaction() stattdessen. (Aber die Idee ist die gleiche.)

    – Julien-L

    10. April 2013 um 0:04 Uhr

Benutzeravatar von Ozone
Ozon

Zu spät zur Party, wollte dies aber nur für zukünftige Referenzen hinzufügen: Wenn Sie Ihren Code in gdb debuggen, vergessen Sie nicht, dass er Ihre Signal-Handler überschreibt.

Wenn Sie also einen Signal-Handler wie zum Beispiel: signal(SIGPIPE, SIG_IGN) eingestellt haben und er nicht zu funktionieren scheint, versuchen Sie, den Code außerhalb des Debuggers auszuführen.

Oder einstellen handle SIGPIPE nostop (in der gdb-Eingabeaufforderung), um zu verhindern, dass gdb auf dem Signal stoppt.

  • Danke für den Tipp für die Zukunft. Aber die gdb zeigte auf die richtige Stelle für SIGPIPE. Vielleicht, weil es ein “harmloses” Signal ist.

    – towi

    4. Oktober 2011 um 6:29 Uhr

  • Warten Sie, Sie sagen also, selbst wenn ich SIGPIPE ignoriere, wenn mein Code unter gdb läuft, bekomme ich immer noch das Signal und mache es erscheinen dass meine Anweisung, das Signal zu ignorieren, nicht funktioniert?

    – Michael

    26. Juli 2012 um 21:15 Uhr

  • Um mir selbst zu antworten, ja. Allerdings mit handle SIGPIPE nostop noprint gdb kann angewiesen werden, es zu ignorieren.

    – Michael

    26. Juli 2012 um 21:52 Uhr

Hast du das zufällig nicht gemacht signal ignorieren, bevor irgendwelche Threads erzeugt werden? Wenn Sie bis später gewartet haben, könnte einer der anderen Threads immer noch das Signal empfangen und Ihre App beenden.

Wenn das nicht reicht, kannst du immer noch schreiben poll/select bevor Sie den Schreibvorgang versuchen, um sicherzustellen, dass der Socket beschreibbar ist.

  • Guter Punkt. Also muss ich das Signal installieren frühere zu jedem Gewinde. Ok, ich werde dafür sorgen, und das schränkt meine Try-and-Error-Fälle auf etwa 30 % ein. Danke. Das Polling war etwas, worüber ich nachgedacht habe, aber das habe ich noch nie bei Sockets gemacht. Werde untersuchen.

    – towi

    26. Juli 2011 um 6:46 Uhr

  • Ich glaube, ich habe es verstanden: Es auf einer sehr äußeren Ebene zu platzieren, immer noch im Inneren main() schien zu helfen. Ich war aber verwirrend gdb bleibt immer wieder am Signal stehen, aber draußen gdb es scheint in Ordnung zu sein.

    – towi

    26. Juli 2011 um 6:51 Uhr

  • Beachten Sie, dass der Ansatz mit poll/select könnte erfolgreich sein, aber das Schreiben könnte aufgrund einer Racebedingung technisch immer noch fehlschlagen – das Lesende der Pipe schließt sich zwischen dem Aufruf an poll/select und write.

    – Tom

    12. Juni 2020 um 0:47 Uhr


Wenn Sie SIGPIPE ignorieren, erhalten Sie kein SIGPIPE-Signal mehr, aber write() bekommt ein EPIPE Error.

1433350cookie-checkWie kann man SIGPIPE verhindern oder verhindern, dass der Server beendet wird?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy