Автоматическое закрытие веб-сокета
Я создаю приложение на Java, которое имеет встроенный сервер веб-сокетов на базе Jetty. Клиент является реализацией веб-сокета по умолчанию в Google Chrome. Все работает нормально, только если нет передачи между сервером и клиентом через определенное время, соединение закрыто. Я не уверен, кто закрывает соединение: сервер Jetty или браузер Chrome.
Я думаю, что решение этой проблемы - отправлять сообщения каждые x секунд, но я открыт для более эффективных решений.
ТАК... мои вопросы:
Это то, что требует протокол websocket, и в этом случае браузер Chrome закрывает мое соединение?
Это что-то более связанное с причалом и более или менее связанное с протоколом websocket? В этом случае, как я могу отключить это в пристани?
Есть ли другая проблема?
Спасибо
ОБНОВЛЕНИЕ: даже если я отправляю 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>
Это сработало для меня, а другие решения - нет!
- Обновите свои jupyters
- Запустите jupyters через предпочитаемый вами блокнот или лабораторию, но добавьте этот код в конец строки в консоли: <--no-browser>
Это избавляет от необходимости постоянно подключаться к вашему экземпляру EC2. Поэтому, даже если вы теряете соединение из-за потери интернет-соединения, всякий раз, когда вы получаете новый доступ к Wi-Fi, он автоматически повторно подключается к активно работающему ядру.
Кроме того, не забудьте запустить свой jupyter в учетной записи tmux, ngnix или других подобных средах.
Надеюсь это поможет!