Socket bleibt bei Close durch Server vorerst geöffnet
-
Hallo Community!
Ich schreib gerade an einer kleinen Server-App und beim Testen fiel mir auf, dass Sockets scheinbar - warum auch immer - trotz Close noch eine Weile geöffnet bleiben. Das allerdings auch nur, wenn der Server die Verbindung schließt.
Zum Testen verwende ich den einfachen Telnet-Client, den mir Windows bietet. Der Server-Part funktioniert soweit eigentlich, die Verbindung wird auch geschlossen (Telnet schmeißt mich mit dem typischen "Verbindung zu Host verloren." raus) - wie gesagt bloß das Problem, dass der Client-Socket auf Server-Seite scheinbar geöffnet bleibt. Ein "netstat -a" ergibt mir zumindest, dass mein Server noch einen Socket zum Client offen hat (Status: wartend), der Client seinen korrekterweise aber bereits geschlossen hat.Folgender Code demonstriert das mal kurz:
class Program { static void Main(string[] args) { TcpListener listener = new TcpListener(IPAddress.Any, 1000) listener.Start(); Socket client = listener.AcceptSocket(); client.Send(Encoding.UTF8.GetBytes("Hello World!")); client.Shutdown(SocketShutdown.Both); client.Disconnect(false); client.Close(); } }
Nach einem "telnet localhost 1000", der gesendeten Nachricht und Rausschmiss durch den Server zeigt ein "netstat -a", dass der Client-Socket im Server noch auf "Wartend" hängt.
Hat eventuell jemand eine Idee, woran das liegen könnte?
Crossposts (da leider keine Antworten):
c-sharp-forum.de
mycsharp.deViele Grüße!
Mao
-
Vielleicht ist's Socket.LingerState.
-
Hallo!
Danke für deine Antwort, aber leider ist es nicht LingerState - keine Veränderung.
(Kann jemand das Problem an seinem Rechner nachvollziehen?)
Viele Grüße!
Mao
-
also ich stecke nicht ganz so tief in der materie, aber auf den ersten blick scheint es so, dass du einen registrierten port verwendest (ports 0-1023 sind reservierte "well-known-ports").
tritt der fehler immernoch auf, wenn du einen port zwischen 49152 und 65535 verwendest? diese ports sind frei programmierbar (dynamic ports).
möglicherweise lauscht ein anderer dienst deines rechners am port 1000 und der socket ist deshalb so oder so offen. ich weiss jetzt leider nicht auswendig, welcher dienst am port 1000 hängt. mehr info dazu findest du auf deinem rechner unter c:\windows\system32\drivers\etc\services (textdatei ohne endung - einfach mit editor öffnen).
btw. kannst du, wenn du mit telnet arbeitest auch port 23 verwenden, der ist für telnet reserviert.
also, die portnummern, die ich meine sind immer serverseitig. beim client wird meistens irgendein port dynamisch zugewiesen und der zielport hat die dienstnummer.
bin leider mit netzwerkprogrammierung nicht so fit, das ist hier nur mein theoretisches uni-wissen. vielleicht konnt ich dir ja doch etwas helfen. ansonsten noch viel erfolg bei der fehlersuche
-
Danke für den Tipp mit den dynamischen Ports, werd ich für später auf jeden Fall beachten.
Am Problem ändert das aber leider nichts.Mir ist nur noch eine kleine "Einschränkung" des Problems aufgefallen: Der Socket bleibt nur auf "wartend" hängen, wenn ich in Telnet während der Sitzung nichts gesendet habe - d.h., wenn ich während ich zum Server verbunden bin eine beliebige Taste im Telnet-Client drücke (die sofort übermittelt wird) und der Server anschließend die Verbindung schließt, bleiben keine "Portrückstände" irgendwo im System kleben.
Für mich wäre es allerdings zum einen natürlich interessant zu wissen, warum das so ist. Viel wichtiger ist es mir allerdings zum Blockieren von DoS-Attacken (Automatisches Schließen der Verbindung nach einer vorgegebenen Zeitspanne, wenn nichts im Socket ankommt). Wär den Server auslasten will, schafft das auch so, aber ich muss ja nicht mehr Angriffsfläche bieten als nötig.
Trotzdem danke!
Mao
-
also mal ganz allgemein zum verbindungsabbruch unter tcp:
client sendet dem server FIN, server antwortet mit FIN ACK (tcp flags in leeren paketen) - bei tcp wird jede anfrage bestätigt. der server kann auch die verbindung abbrechen, indem er RST an den client sendet.
das ist allerdings "low level" tcp kommunikation. ich weiss nicht, inwiefern dein framework dies automatisch tut. ich empfehle dir, z.b. den tcp artikel auf wikipedia zu lesen, der ist ganz gut soweit. und dann schnapp dir einen sniffer (z.b. wireshark) und log den traffic mit. damit findest du auf jeden fall den grund, auch wenn es vielleicht etwas aufwändig ist. aber es hilft allgemein tcp kommunikation besser zu verstehen und solider mit solchen sachen umgehen zu können.
worauf ich hinaus will: wenn dein server von sich aus die verbindung abbricht, wie du sagst, scheint es ja zu klappen (also RST). also besteht das problem, wenn der client abbricht? könnte es sein, dass der server, aus welchem grund auch immer, kein FIN ACK (finish acknowledge) sendet? das würde bedeuten, dass er die verbindungsbeendung nicht mitbekommen hat und noch denkt, dass vom client noch was kommt und nun wartet, bis sein timer ausläuft, was bis zu 10 minuten dauern kann. hast du in deinem programm serverseitig korrekt auf den verbindungsabbruch reagiert (bzw den server überhaupt selbst geschrieben)?
da würde ich ansetzen
-
Die konkrete TCP/IP-Kommunikation übernimmt für mich das .Net-Framework. Der Server ist - unter Verwendung von .Net - selbstgeschrieben, ein viel kürzerer Code, der das selbe Problem hat, ist in meinem Start-Posting zu sehen.
Was .Net konkret an Steuerungsinformation sendet oder nicht sendet, da hab ich wahrscheinlich recht wenig Einfluss drauf. Aber ich könnt mal, wie von dir erwähnt, mit einem Sniffer draufschaun.Was ich für meinen Zweck brauche ist wie gesagt ein möglichst vollständiges Abbrechen der Kommunikation, auch wenn der Client nicht in der Lage ist - oder wie im Fall einer DoS-Attacke gar nicht gewillt ist -, den Verbindungsabbruch meinerseits zu bestätigen.
Aber aus irgendeinem Grund scheint der obige Code das nicht vollständig durchzuziehen - der Client selbst wird rausgeschmissen ("Verbindung zu Host verloren."), aber server-seitig hängt die Verbindung zum Client auf "wartend".Viele Grüße!
Mao
-
Verhält sich vielleicht "TcpClient client = server.AcceptTcpClient();" anders?
-
okay, ich fürchte dann kann ich dir im detail mit .net nicht weiterhelfen, das müsste ich mir erst selbst anschauen. was ich über netzwerkkommunikation weiss ist wohl zu allgemein.
probier mal ruhig das mit dem sniffer aus. wenn man konkret sieht, was übers netz geht ist das oft eine große hilfe
wünsche dir noch viel erfolg bei der fehlersuche und einen schönen sonntag
-
@hajb:
Gerade getestet mit TcpClient, leider selbes Ergebnis.@jule37:
Ja, ich werd dem Stückchen Code dann mal mit dem Sniffer zu Leibe rücken.wünsche dir noch viel erfolg bei der fehlersuche und einen schönen sonntag
Danke, dir auch!
Was mir noch so eben durch den Kopf ging: Ein Problem, das weder an mir, noch an .Net hängt?
/edit: Tags korrigiert.
Viele Grüße!
Mao