Websocket schließt die Verbindung automatisch

77

Ich erstelle eine Anwendung in Java, die einen eingebetteten Websocket-Server hat, der auf Jetty basiert. Der Client ist die Standard-Websocket-Implementierung in Google Chrome. Alles funktioniert in Ordnung, nur wenn nach einer bestimmten Zeit, in der die Verbindung geschlossen wird, keine Übertragung zwischen Server und Client erfolgt. Ich bin nicht sicher, wer die Verbindung schließt: der Steg-Server oder der Chrome-Browser.

Ich denke, die Lösung dafür besteht darin, alle x Sekunden eine Nachricht zu senden, aber ich bin offen für bessere Lösungen.

SO ... meine Fragen sind:

  1. Ist dies etwas, das das Websocket-Protokoll erfordert, und in diesem Fall schließt der Chrome-Browser meine Verbindung?

  2. Ist dies etwas, das mehr mit dem Steg zusammenhängt und mehr oder weniger mit dem Websocket-Protokoll zu tun hat? Wie deaktiviere ich dies in diesem Fall im Steg?

  3. Gibt es ein anderes Problem?

Vielen Dank

UPDATE: Auch wenn ich 1 Nachricht / Sekunde sende, ist die Verbindung geschlossen

Doua Beri
quelle
1
Haben Sie einen Proxy zwischen dem Client und dem Server? Es ist bekannt, dass Proxies manchmal Websockets schließen ( stackoverflow.com/questions/9017113/… )
ndeverge
Ich benutze Jetty und habe das gleiche Problem. Kein Proxy - Ich habe einen Server auf localhost mit dem Browser auf demselben Computer.
Ant Kutschera
mmm testest du es auf Internet Explorer? weil ich immer noch unter diesem seltsamen IE-Verhalten leide: connect.microsoft.com/IE/feedback/details/804653/…
Plastic

Antworten:

48

Als Antwort auf Ihre dritte Frage: Ihr Client möchte ohnehin in der Lage sein, vorübergehende Netzwerkprobleme zu bewältigen. Nehmen wir beispielsweise an, der Benutzer schließt seinen Laptop zwischen Besprechungen, die ihn in den Ruhezustand versetzen, oder das Netzwerk fällt einfach vorübergehend aus.

Die Lösung besteht darin, oncloseEreignisse auf dem Web-Socket-Client abzuhören und bei Auftreten ein clientseitiges Zeitlimit festzulegen, um die Verbindung erneut zu öffnen, z. B. in einer Sekunde:

function setupWebSocket(){
    this.ws = new WebSocket('wss://host:port/path');
    this.ws.onerror = ...;
    this.ws.onopen = ...;
    this.ws.onmessage = ...;
    this.ws.onclose = function(){
        setTimeout(setupWebSocket, 1000);
    };
}
Ameise Kutschera
quelle
10

Ich fand eine andere, ziemlich schnelle und schmutzige Lösung. Wenn Sie den WebSocket auf niedriger Ebene implementieren und die onOpenMethode selbst implementieren, erhalten Sie ein Objekt, das die WebSocket.ConnectionSchnittstelle implementiert . Dieses Objekt verfügt über eine setMaxIdleTime- Methode, die Sie anpassen können.

LeoR
quelle
7

Sie können das Timeout-Intervall in der serverseitigen Jetty-Konfiguration mithilfe der WebSocketServletFactoryInstanz festlegen . Zum Beispiel:

WebSocketHandler wsHandler = new WebSocketHandler() {
    @Override
    public void configure(WebSocketServletFactory factory) {
        factory.getPolicy().setIdleTimeout(1500);
        factory.register(MyWebSocketAdapter.class);
        ...
    }
}
user3499459
quelle
4

Habe gerade die Lösung für mich gefunden. Was Sie einstellen möchten, ist die maxIdleTime von WebSocketServlet in Millis. Wie das geht, hängt davon ab, wie Sie Ihr Servlet konfigurieren. Mit Guice ServletModule können Sie so etwas für eine Zeitüberschreitung von 10 Stunden tun:

serve("ws").with(MyWSServlet.class, 
new HashMap<String, Sring>(){{ put("maxIdleTime", TimeUnit.HOURS.toMillis(10) + ""); }});

Alles <0 ist eine unendliche Leerlaufzeit, glaube ich.

AkaZn
quelle
3

Ich glaube, das ist ein Stegproblem. Ich habe keine Browser gesehen, die WebSocket-Verbindungen aufgrund von Inaktivität geschlossen haben, und ich habe auch keine anderen WebSocket-Server gefunden, bei denen WebSocket-Verbindungen zeitlich begrenzt sind.

Jetty konzentriert sich (war) hauptsächlich auf das Erstellen von HTTP-basierten Anwendungsservlets. In diesem Zusammenhang müssen HTTP-Verbindungen ziemlich aggressiv bereinigt werden, und HTTP wurde nicht für langlebige Verbindungen entwickelt, sodass ein kurzes Standardzeitlimit angemessen ist.

Ich habe das von Ihnen beschriebene genaue Problem nicht gesehen (Schließen auch bei Aktivität), aber ich sehe, dass WebSocket-Verbindungen nach 30 Sekunden Inaktivität geschlossen werden. Es ist möglich, dass in älteren Versionen von Jetty oder in der aktuellen Version aus einem anderen Grund der Timer nicht durch WebSocket-Aktivitäten zurückgesetzt wird. Um dieses Problem zu umgehen, verwende ich die setMaxIdleTime-Methode für mein BlockingChannelConnector-Objekt, um den Timeout-Wert auf Integer MAX_VALUE zu setzen.

Kanaka
quelle
2

Ich denke, dieses Timeout ist tatsächlich Teil von TCP / IP und die Lösung besteht darin, nur ab und zu leere Nachrichten zu senden.

David Grayson
quelle
1
hey danke .. aber das hilft mir nicht. Ich habe es gerade mit 1 Nachricht pro Sekunde versucht und die Verbindung wird immer noch geschlossen
Doua Beri
David, kannst du das belegen? Nach meinem Verständnis überlässt TCP Richtlinienentscheidungen wie das Leerlaufzeitlimit der Anwendung, dem Betriebssystem und der Netzwerkinfrastruktur (TCP versucht, richtlinienunabhängig zu sein). Vielleicht denken Sie an Keep-Alive, bei dem es sich um regelmäßige Nachrichten handelt, um sicherzustellen, dass die Verbindung nicht stillschweigend unterbrochen wurde (wodurch die Verbindung normalerweise nach 2 Stunden unterbrochen wird).
Kanaka
@kanaka Ich habe das irgendwo gelesen, aber ich kann es nicht wirklich sichern. Ich weiß mit Sicherheit, dass ich beim Schreiben meines eigenen Websocket-Servers mit Python ab und zu eine leere Nachricht senden musste, um zu verhindern, dass die Verbindung getrennt wird.
David Grayson
Dies ist nicht Teil von TCP / IP, kann jedoch das Ergebnis einer Stateful Firewall sein, die den Status der Verbindung verliert, weil sie zu lange inaktiv war. Wahrscheinlich denken Sie an TCP Keepalives, die dieses Problem lösen.
David Hoelzer
2

Hier ist ein Beispiel zum Konfigurieren des Websocket-Timeouts von Jetty (der wahrscheinlichste Schuldige) mithilfe von WebSocketServlet (in Scala, sorry, aber die Syntax ist ziemlich gleich).

import javax.servlet.annotation.WebServlet
import org.eclipse.jetty.websocket.servlet.{WebSocketServletFactory, WebSocketServlet}

@WebServlet(name = "WebSocket Servlet")
class WebsocketServlet extends WebSocketServlet {
  override def configure(factory: WebSocketServletFactory): Unit = {
    factory.getPolicy.setIdleTimeout(1000 * 3600)
    factory.register(classOf[ClientWebsocket])
  }
}
user1338062
quelle
1

Ich habe eine ähnliche Erfahrung und glaube, dass es der Browser sein könnte, der die Sitzung abbricht. Ich habe auch das maxIdleTimeout festgelegt, aber die Sitzung wird trotzdem abgebrochen. Für mich sieht es so aus, als ob der Client (der Browser) die Sitzung zeitlich begrenzt und dann auflegt.

Ich weiß nicht, wie ich es umgehen soll.

AndersW
quelle
0

Gleiches Problem: Verwenden Sie die Bibliothek WebSockets & sockjs-client / 1.0.3 / sockjs mit @ServerEndPoint auf der Java Server-Seite. Die Websocket-Verbindungen brachen immer wieder unterschiedlich.

Ich habe Stomp und sockJS verwendet (@ServerEndpoint verlassen), bin aber auf ein anderes Problem gestoßen, das bei SO beliebt ist - / info = 34424 - mit 404-Fehler -

Ich musste die Verwendung des XML-Ansatzes der Stomp Spring-Bibliothek aufgeben, wie an anderen Stellen vorgeschlagen. Ich habe Spring 4.2 in meinem Projekt und viele SockJS Stomp-Implementierungen funktionieren normalerweise gut mit Spring Boot-Implementierungen. Diese Implementierung von Baeldung hat funktioniert (für mich ohne Wechsel von Spring 4.2 auf 5).

Nachdem ich die in seinem Blog erwähnten Abhängigkeiten verwendet hatte, gab es mir immer noch ClassNotFoundError. Ich habe die folgende Abhängigkeit hinzugefügt, um das Problem zu beheben.

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.2.3.RELEASE</version>
    </dependency>
veritas
quelle
0

Dies funktionierte für mich, während die anderen Lösungen nicht waren!

  1. Aktualisieren Sie Ihre Jupyters
  2. Starten Sie Ihre Jupyters über Ihr bevorzugtes Notizbuch oder Labor, aber fügen Sie diesen Code am Ende der Zeile in der Konsole hinzu: <--no-browser>

Dies hört auf, ständig mit Ihrer EC2-Instanz verbunden zu sein. Selbst wenn Sie aufgrund eines Internetverbindungsverlusts die Verbindung verlieren, wird die Verbindung zum aktiv funktionierenden Kernel automatisch wiederhergestellt, wenn Sie einen neuen WLAN-Zugang erhalten.

Vergessen Sie auch nicht, Ihren Jupyter in einem tmux-Konto oder einem ngnix oder einer anderen Umgebung wie dieser zu starten.

Hoffe das hilft!

Selin Tosun
quelle
0

Da bei @Doua Beri die Verbindung auch bei 1-Hz-SENDs geschlossen wird, kann dies an Größenbeschränkungen für Nachrichten liegen.

Diese Passage aus Spring's WebSockets kann nützlich sein, mit meinem Schwerpunkt ...

Obwohl theoretisch die Größe einer WebSocket-Nachricht nahezu unbegrenzt sein kann, setzen WebSocket-Server in der Praxis Grenzen - zum Beispiel 8 KB bei Tomcat und 64 KB bei Jetty . Aus diesem Grund teilen STOMP-Clients wie stomp.js größere STOMP-Nachrichten an 16-KB-Grenzen auf und senden sie als mehrere WebSocket-Nachrichten, sodass der Server puffern und neu zusammenstellen muss.

Ken Lin
quelle