Socket: Send auf geschlossenen TCP-Socket

Gast #6742080
Lesenswert?

Hi zusammen,
ich stehe gerade etwas auf dem Schlauch:
Momentan arbeite ich an einem TCP-Server. Wenn der Client die Verbindung 
beendet und der Server danach ein Send() macht, dann stürzt der Server 
mit der Exception "external: SIGPIPE" ab.
Das ist doof.

aktuell sieht die Sende-Routine bei mir etwa so aus:
a) select() auf TX-Event
b) send();

Wie kann ich denn auf Server-Seite prüfen, ob der Client noch da ist?
Die Idee mit dem select() auf TX hatte ich mal irgendwo gelesen, aber 
das funktioniert hier irgendwie nicht :(
Mit einem Fehler im Return-Code könnte ich super leben, aber Absturz ist 
halt auf Dauer unbrauchbar...

Falls es etwas hilft:
Lazarus unter Linux Mint 18.3
select() und send() sind aus dem fpc-Wrapper fpselect() und fpsend(). 
Die sollten aber 1:1 auf die Linux-Funktionen gehen.
Codeschnipsel müßte ich erst generieren (ist über ein paar Klassen in 
meinen eigenen Bibliotheken verteilt).
Mit UDP hatte ich mit den selbst (Basis-)Klassen bislang nie Probleme, 
aber das liegt wahrscheinlich an der Verbindungslosigkeit

Freue mich über jeden konzeptionellen Tip! :)
Mir geht es hier wirklich um das Verständnis ums Konzept "Erkennen einer 
geschlossenen TCP-Verbindung", nicht um das Zusammenkopieren von 
Codeschnipseln!

Danke und VG
Gast #6742102
Lesenswert?

Hi A.K.
vielen Dank! Das ging ja schnell :)

Gerade wollte ich schreiben:
Ich hätte früher fragen sollen, dann wäre ich auch früher in den 
manpages über MSG_NOSIGNAL gefallen...

Viele Grüße!
Gast #6742702
Lesenswert?

Hi, hier noch eine  „konzeptionelle Anmerkung“:

Das Flag-Bit MSG_NOSIGNAL löst das Problem des Absturzes bei nicht 
abgefangenem SIGPIPE.  Dieses Flag kann man sowieso immer setzen (und 
natürlich auch immer die Returncodes auswerten!).

Das SIGPIPE entsteht, weil der Server noch versucht Daten zu senden, 
obwohl auch der lokale Socket schon weg ist. Der lokale Socket wird vom 
Client dadurch geschlossen, das der Reset (RST) schickt. Ein Reset kommt 
entweder weil auf dem Client ein „abortive Shutdown“ programmiert ist 
(SO_LINGER mit Intervall 0 (setsockopt()) und anschließend ein close()) 
oder weil nach dem close() des Clients nach Ablauf des 
Linger-Intervalls noch Daten beim Client  ankommen.

Das kann man auch im Server  Programm berücksichtigen und das Problem 
möglicherweise allein damit lösen.  Dazu muss man mit dem select() auch 
den readfds  abfragen. Wenn der Client die Verbindung schließt, ob 
graceful oder nicht, dann setzt select()  das Bit für read und man 
empfängt  mit recv() 0 Byte und bekommt einen Returncode. Dann kann der 
Server ebenfalls die Verbindung schließen ohne unnötig weiter Daten zu 
senden.

Wenn der Server allerdings Daten wie ein Fileserver sendet und deshalb 
beim Close oder Abbruch durch den Client schon genügend unterwegs sind, 
dann kann es wieder zu „broken pipe“ kommen. Deshalb, siehe oben, immer 
das Flag-Bit setzen :-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren