Автоматическое закрытие веб-сокета

Я создаю приложение на Java, которое имеет встроенный сервер веб-сокетов на базе Jetty. Клиент является реализацией веб-сокета по умолчанию в Google Chrome. Все работает нормально, только если нет передачи между сервером и клиентом через определенное время, соединение закрыто. Я не уверен, кто закрывает соединение: сервер Jetty или браузер Chrome.

Я думаю, что решение этой проблемы - отправлять сообщения каждые x секунд, но я открыт для более эффективных решений.

ТАК... мои вопросы:

  1. Это то, что требует протокол websocket, и в этом случае браузер Chrome закрывает мое соединение?

  2. Это что-то более связанное с причалом и более или менее связанное с протоколом websocket? В этом случае, как я могу отключить это в пристани?

  3. Есть ли другая проблема?

Спасибо

ОБНОВЛЕНИЕ: даже если я отправляю 1 сообщение / секунду, соединение закрыто

9 ответов

В ответ на ваш третий вопрос: ваш клиент в любом случае хочет иметь возможность справиться с временными проблемами в сети, например, допустим, что пользователь закрывает свой ноутбук между совещаниями, которые его переводят в спящий режим, или сеть просто временно отключается.

Решение состоит в том, чтобы слушать onclose события на клиенте веб-сокета и, когда они происходят, установите время ожидания на стороне клиента, чтобы повторно открыть соединение, скажем, в секунду:

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);
    };
}

Вам нужно время от времени отправлять сообщения ping. Я думаю, что время ожидания по умолчанию составляет 300 секунд. Отправка пинг / понг фрейма через браузер

Я нашел другое, довольно быстрое и грязное решение. Если вы используете низкоуровневый подход для реализации WebSocket и вы реализуете onOpen Метод самостоятельно вы получаете объект, реализующий WebSocket.Connection интерфейс. Этот объект имеет метод setMaxIdleTime, который вы можете настроить.

Фактически вы можете установить интервал ожидания в конфигурации на стороне сервера Jetty, используя экземпляр WebSocketServletFactory. Например:

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

Просто нашел решение этого для себя. То, что вы хотите установить, это maxIdleTime WebSocketServlet, в миллис. Как это сделать, зависит от того, как вы настроили свой сервлет. С Guice ServletModule вы можете сделать что-то подобное в течение 10 часов:

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

Все, что <0, бесконечно просто, я верю.

Я думаю, что этот тайм-аут на самом деле является частью TCP/IP, и решение состоит в том, чтобы просто время от времени отправлять пустые сообщения.

Я считаю, что это проблема причала. Я не видел ни одного браузера, закрывающего соединения WebSocket из-за неактивности, и не сталкивался с другими серверами WebSocket, которые превышают время ожидания соединений WebSocket.

Jetty (был) в основном сосредоточен на создании сервлетов приложений на основе HTTP. В этом контексте HTTP-соединения необходимо очищать довольно агрессивно, а HTTP не был разработан для долговременных соединений, поэтому разумно иметь короткий тайм-аут по умолчанию.

Я не видел точную проблему, которую вы описали (закрытие даже с активностью), но я вижу, что соединения WebSocket закрываются после 30 секунд бездействия. Вполне возможно, что в более старых версиях Jetty или в текущей версии по какой-либо другой причине таймер не сбрасывается активностью WebSocket. Я обхожу это, используя метод setMaxIdleTime в моем объекте BlockingChannelConnector, чтобы установить значение тайм-аута в Integer MAX_VALUE.

Вот пример того, как настроить время ожидания веб-сокета Jetty (наиболее вероятный виновник) с помощью WebSocketServlet (в scala, извините, но синтаксис почти такой же).

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])
  }
}

Поскольку @Doua Beri обнаруживает, что соединение закрывается даже при 1 Гц SEND, это может быть связано с ограничениями на размер сообщений.

Этот отрывок из Spring WebSockets может быть полезен, с моей точки зрения...

Хотя теоретически сообщение WebSocket может быть практически неограниченным по размеру, на практике серверы WebSocket накладывают ограничения - например, 8 КБ на Tomcat и 64 КБ на Jetty. По этой причине клиенты STOMP, такие как stomp.js, разделяют большие сообщения STOMP на границах 16 КБ и отправляют их как несколько сообщений WebSocket, что требует от сервера буферизации и повторной сборки.

У меня есть похожий опыт, и я считаю, что браузер может сократить время сеанса. Я также установил maxIdleTimeout, но сеанс отбрасывается независимо. Для меня это выглядит так, будто клиент (браузер) рассчитывает время сеанса, а затем зависает.

Не знаю, как обойти это.

Та же проблема: использовалась библиотека WebSockets и sockjs-client/1.0.3/sockjs с @ServerEndPoint на стороне Java Server. Соединения с веб-сокетами постоянно прерывались.

Я перешел на использование Stomp и sockJS (отказавшись от @ServerEndpoint), но столкнулся с другой проблемой, популярной в SO - /info=34424 - с ошибкой 404 -

Мне пришлось отказаться от использования xml-подхода библиотеки Stomp Spring, как предлагалось в других местах. В моем проекте есть Spring 4.2, и многие реализации SockJS Stomp обычно хорошо работают с реализациями Spring Boot. Эта реализация от Baeldung работала (для меня без перехода с Spring 4.2 на 5).

После использования зависимостей, упомянутых в его блоге, он все еще дал мне ClassNotFoundError. Я добавил приведенную ниже зависимость, чтобы исправить это.

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

Это сработало для меня, а другие решения - нет!

  1. Обновите свои jupyters
  2. Запустите jupyters через предпочитаемый вами блокнот или лабораторию, но добавьте этот код в конец строки в консоли: <--no-browser>

Это избавляет от необходимости постоянно подключаться к вашему экземпляру EC2. Поэтому, даже если вы теряете соединение из-за потери интернет-соединения, всякий раз, когда вы получаете новый доступ к Wi-Fi, он автоматически повторно подключается к активно работающему ядру.

Кроме того, не забудьте запустить свой jupyter в учетной записи tmux, ngnix или других подобных средах.

Надеюсь это поможет!

Другие вопросы по тегам