16 Stimmen

Wie man erkennt, wann eine Socket-Verbindung getrennt wurde

Auf der Client-Seite muss ich wissen, wann/ob meine Socket-Verbindung unterbrochen wurde. Allerdings gibt die Socket.Connected-Eigenschaft immer true zurück, auch nachdem die Server-Seite getrennt wurde und ich versucht habe, Daten durch sie zu senden. Kann mir jemand helfen herauszufinden, was hier vor sich geht? Ich muss wissen, wann ein Socket getrennt wurde.

Socket serverSocket = null;
TcpListener listener = new TcpListener(1530);
listener.Start();
listener.BeginAcceptSocket(new AsyncCallback(delegate(IAsyncResult result)
{
    Debug.WriteLine("SOCKET-VERBINDUNG WIRD AKZEPTIERT");
    TcpListener currentListener = (TcpListener)result.AsyncState;
    serverSocket = currentListener.EndAcceptSocket(result);
}), listener);

Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Debug.WriteLine("Client-Socket verbunden: " + clientSocket.Connected);//sollte FALSE sein, und das ist es
clientSocket.Connect("localhost", 1530);
Debug.WriteLine("Client-Socket verbunden: " + clientSocket.Connected);//sollte TRUE sein, und das ist es

Thread.Sleep(1000);
serverSocket.Close();//Schließen des Server-Sockets hier
Thread.Sleep(1000);

clientSocket.Send(new byte[0]);//Das Senden von Daten sollte dazu führen, dass der Socket seine Eigenschaft Connected aktualisiert.
Debug.WriteLine("Client-Socket verbunden: " + clientSocket.Connected);//sollte FALSE sein, aber es ist immer TRUE

10voto

Daniel Stutzbach Punkte 69710

Nach einigen Tests scheint es, dass die Dokumentation für Socket.Connected falsch ist oder zumindest irreführend. clientSocket.Connected wird erst false, nachdem clientSocket.close() aufgerufen wurde. Ich denke, das ist eine Rückbesinnung auf die ursprüngliche C Berkeley Sockets API und ihre Terminologie. Ein Socket ist gebunden, wenn ihm eine lokale Adresse zugeordnet ist, und ein Socket ist verbunden, wenn ihm eine entfernte Adresse zugeordnet ist. Auch wenn die entfernte Seite die Verbindung geschlossen hat, hat der lokale Socket immer noch die Zuordnung und ist daher immer noch "verbunden".

Hier ist jedoch eine Methode, die funktioniert:

!(socket.Poll(0, SelectMode.SelectRead) && socket.Available == 0)

Sie stützt sich darauf, dass eine geschlossene Verbindung als lesbar markiert wird, auch wenn keine Daten verfügbar sind.

Wenn Sie Bedingungen wie defekte Netzwerkkabel oder plötzlich ausgeschaltete Computer erkennen möchten, ist die Situation etwas komplexer. Unter diesen Bedingungen erhält Ihr Computer nie ein Paket, das darauf hinweist, dass der Socket geschlossen wurde. Er muss erkennen, dass die entfernte Seite verschwunden ist, indem er Pakete sendet und feststellt, dass keine Antwort zurückkommt. Sie können dies auf Anwendungsebene als Teil Ihres Protokolls tun, oder Sie können die TCP KeepAlive-Option verwenden. Die Verwendung von TCP Keep Alive von .NET aus ist nicht besonders einfach; Sie sind wahrscheinlich besser dran, einen Keep-Alive-Mechanismus in Ihr Protokoll zu integrieren (alternativ könnten Sie eine separate Frage stellen, wie Sie TCP Keep Alive in .NET aktivieren und das Keep-Alive-Intervall festlegen können).

4voto

Mark Brackett Punkte 83046

Schreiben Sie einfach wie gewohnt an Ihren Socket. Sie werden wissen, wenn er getrennt ist, durch die Exception, die besagt, dass Ihre Daten nicht übermittelt werden konnten.

Wenn Sie nichts zu schreiben haben... wen kümmert es, ob er getrennt ist? Vielleicht ist er jetzt getrennt, aber kommen Sie zurück, bevor Sie ihn brauchen - warum ihn abreißen und dann eine erneute Verbindung herstellen, bis die Verbindung repariert ist... besonders wenn Sie sowieso nichts zu sagen hatten?

Wenn es Sie stört, implementieren Sie ein Keep-Alive in Ihrem Protokoll. Dann haben Sie alle 30 Sekunden oder so etwas zu sagen.

3voto

Migol Punkte 7802

Vielleicht ist die Lösung, einige Dummy-Daten durchzuschicken und zu überprüfen, ob es Zeitüberschreitungen gibt?

2voto

tggagne Punkte 2794

Ich empfehle, die sprachlichen Elemente auf höherer Ebene zu entfernen und zu erforschen, was auf der Ebene von IO auf niedrigerer Ebene passiert.

Das niedrigste, was ich erkundet habe, war das Schreiben von isectd (zu finden auf Sourceforge). Durch Verwendung des select() Systemaufrufs wird ein Deskriptor für einen geschlossenen Socket lesebereit, und wenn isectd versucht, den recv() Aufruf auszuführen, kann der getrennte Zustand des Sockets bestätigt werden.

Als Lösung empfehle ich, Ihr eigenes Socket-IO nicht selbst zu schreiben und die Middleware eines anderen zu verwenden. Es gibt viele gute Kandidaten da draußen. Vergessen Sie auch nicht, einfache Warteschlangendienste in Betracht zu ziehen.

PS. Ich hätte URLs zu all dem oben Genannten bereitgestellt, aber meine Reputation (1) erlaubt es nicht.

0voto

Seth M. Punkte 598

Wartet die clientSocket.Send() Methode darauf, dass das Paket entweder bestätigt oder abgelehnt wird?

Wenn nicht, fliegt Ihr Code zur nächsten Zeile, während der Socket immer noch versucht herauszufinden, was passiert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X