.NET WebSockets werden trotz Keep-Alive und Aktivität auf der Verbindung zwangsweise geschlossen

9

Wir haben einen einfachen WebSocket-Client mit System.Net.WebSockets geschrieben. Der KeepAliveInterval auf der ClientWebSocket ist auf 30 Sekunden festgelegt.

Die Verbindung wird erfolgreich geöffnet und der Datenverkehr fließt wie erwartet in beide Richtungen. Wenn die Verbindung inaktiv ist, sendet der Client alle 30 Sekunden Pong-Anfragen an den Server (sichtbar in Wireshark).

Aber nach 100 Sekunden wird die Verbindung abrupt beendet, weil der TCP-Socket auf Client-Seite geschlossen wird (wir beobachten in Wireshark, dass der Client ein FIN sendet). Der Server antwortet mit einem 1001 Going Away, bevor er den Socket schließt.

Nach vielen Ausgrabungen haben wir die Ursache aufgespürt und eine ziemlich umständliche Problemumgehung gefunden. Trotz vieler Google- und Stack-Overflow-Suchen haben wir nur ein paar andere Beispiele von Leuten gesehen, die über das Problem berichten und niemand mit einer Antwort, also poste ich das, um anderen die Schmerzen zu ersparen und in der Hoffnung, dass jemand dazu in der Lage ist um eine bessere Problemumgehung vorzuschlagen.

Die Quelle des 100-Sekunden-Zeitlimits besteht darin, dass WebSocket einen System.Net.ServicePoint verwendet, der über eine MaxIdleTime-Eigenschaft verfügt, um das Schließen leerer Sockets zu ermöglichen. Beim Öffnen des WebSockets, wenn ein vorhandener ServicePoint für den Uri vorhanden ist, wird dieser verwendet, unabhängig davon, auf welche Eigenschaft die MaxIdleTime-Eigenschaft beim Erstellen festgelegt wurde. Wenn nicht, wird eine neue ServicePoint-Instanz erstellt, wobei MaxIdleTime vom aktuellen Wert der MaxServicePointIdleTime-Eigenschaft System.Net.ServicePointManager (standardmäßig 100.000 Millisekunden) festgelegt wird.

Das Problem besteht darin, dass weder der WebSocket-Datenverkehr noch der WebSocket-Keep-Alive (Ping / Pong) sich als Datenverkehr zu registrieren scheinen, solange der ServicePoint-Leerlauftimer betroffen ist. So genau 100 Sekunden nach dem Öffnen des WebSockets wird er trotz Traffic oder Keep-Alive einfach abgerissen.

Wir vermuten, dass dies daran liegt, dass der WebSocket als HTTP-Anfrage beginnt, die dann zu einem Websocket hochgestuft wird. Es scheint, dass der Leerlauf-Timer nur nach HTTP-Datenverkehr sucht. Wenn das tatsächlich passiert, scheint das ein großer Fehler in der System.Net.WebSockets-Implementierung zu sein.

Die Problemumgehung, die wir verwenden, besteht darin, die MaxIdleTime für den ServicePoint auf int.MaxValue festzulegen. Dadurch kann der WebSocket unbegrenzt geöffnet bleiben. Der Nachteil ist jedoch, dass dieser Wert für alle anderen Verbindungen für diesen ServicePoint gilt. In unserem Kontext (bei dem es sich um einen Auslastungstest mit Visual Studio Web- und Load-Tests handelt) haben wir andere (HTTP-) Verbindungen für denselben ServicePoint geöffnet, und tatsächlich ist bereits eine aktive ServicePoint-Instanz vorhanden, wenn wir unseren WebSocket öffnen. Dies bedeutet, dass nach dem Update der MaxIdleTime alle HTTP-Verbindungen für den Auslastungstest kein Leerlaufzeitlimit haben. Dies fühlt sich nicht ganz angenehm an, obwohl der Webserver in der Praxis trotzdem Leerlaufverbindungen schließen sollte.

Wir untersuchen auch kurz, ob wir eine neue ServicePoint-Instanz erstellen können, die nur für unsere WebSocket-Verbindung reserviert ist, sehen aber keinen sauberen Weg.

Eine weitere kleine Wendung, die das Aufspüren erschwert hat, ist, dass die MaxServicePointIdleTime-Eigenschaft von System.Net.ServicePointManager standardmäßig 100 Sekunden lang ist. Visual Studio überschreibt diesen Wert jedoch und setzt ihn auf 120 Sekunden - was die Suche schwieriger machte .

    
Richard Leeke 09.11.2016, 08:51
quelle

1 Antwort

5

Ich bin diese Woche auf diese Ausgabe gestoßen. Ihr Workaround hat mich in die richtige Richtung geführt, aber ich glaube, ich habe die Ursache eingegrenzt.

Wenn ein Header "Content-Length: 0" in der Antwort "101 Switching Protocols" von einem WebSocket-Server enthalten ist, wird WebSocketClient verwirrt und plant die Verbindung in 100 Sekunden für die Bereinigung.

Hier ist der fehlerhafte Code aus der .Net-Referenzquelle :

%Vor%

Gemäß RFC 7230 Abschnitt 3.3.2 ist Content-Length in 1xx (informativen) Nachrichten verboten, aber ich habe festgestellt, dass es irrtümlicherweise in einigen Serverimplementierungen enthalten ist.

Weitere Details, einschließlich einiger Beispielcodes zum Diagnostizieren von ServicePoint-Problemen, finden Sie in folgendem Thread: Ссылка

    
Doug Drinka 14.06.2017 19:49
quelle

Tags und Links