Forum: PC-Programmierung Socket: Send auf geschlossenen TCP-Socket


von Netzwerker (Gast)


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

von (prx) A. K. (prx)


Lesenswert?

signal(SIGPIPE, SIG_IGN);

von (prx) A. K. (prx)


Lesenswert?

PS: Ein Wiedergänger. Siehe 
Beitrag "[C] TCP Client Problem Linux".

von Netzwerker (Gast)


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!

von socket workman (Gast)


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 :-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.