автоматичне закриття з'єднання з веб - сокетом


77

Я будую додаток у Java, який має вбудований сервер веб-сокетів на основі jetty. Клієнт - це веб-розетка за замовчуванням, реалізована в google chrome. Все працює нормально, лише якщо через певний час з'єднання між сервером і клієнтом не буде перенесено. Я не впевнений, хто замикає з'єднання: сервер причалу або браузер Chrome.

Рішенням цього, я думаю, є відправлення повідомлення кожні x секунд, але я відкритий для кращих рішень.

ТАК ... мої запитання такі:

  1. Це щось, що вимагає протокол websocket, і в цьому випадку браузер chrome закриває моє з’єднання?

  2. Це щось більше пов'язане з причалом і має більш-менш спільне з протоколом websocket? У цьому випадку, як мені відключити це на пристані?

  3. Чи є ще одна проблема ??

Дякую

ОНОВЛЕННЯ: навіть якщо я відправляю 1 повідомлення на секунду, все одно з'єднання буде закрито


1
Чи є у вас проксі-сервер між клієнтом і сервером? Довірені відомі іноді близькі WebSockets ( stackoverflow.com/questions/9017113 / ... )
ndeverge

Я використовую Jetty, і у мене така ж проблема. Немає проксі-сервера - у мене є сервер на localhost з браузером на тій самій машині.
Ant Kutschera

ммм, ви тестуєте це в Internet Explorer ?? тому що я все ще страждаю через цю дивну поведінку IE: connect.microsoft.com/IE/feedback/details/804653/…
Пластик,

Відповіді:


48

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

Рішення полягає в тому, щоб прослуховувати 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);
    };
}


10

Я знайшов інше, досить швидке та брудне рішення. Якщо ви використовуєте підхід низького рівня для реалізації WebSocket, і ви реалізуєте onOpenметод самостійно, ви отримуєте об'єкт, що реалізує WebSocket.Connectionінтерфейс. Цей об’єкт має метод setMaxIdleTime, який ви можете налаштувати.


8

Ви можете фактично встановити інтервал очікування в конфігурації на стороні сервера Jetty, використовуючи WebSocketServletFactoryекземпляр. Наприклад:

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

4

Просто знайшов для себе рішення цього. Що ви хочете встановити, це maxIdleTime WebSocketServlet, у мілісекундах. Як це зробити, залежить від того, як ви налаштували свій сервлет. За допомогою Guice ServletModule ви можете зробити щось подібне для часу очікування 10 годин:

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

Я вважаю, що все <0 - це нескінченний час простою.


3

Я вважаю, що це проблема пристані. Я не бачив, щоб жоден браузер закривав з’єднання WebSocket через бездіяльність, а також не стикався з іншими серверами WebSocket, які таймаутували з’єднання WebSocket.

Jetty (в основному) орієнтований на створення сервлетів додатків на основі HTTP. У цьому контексті з'єднання HTTP потрібно очищати досить агресивно, і HTTP не був розроблений для довготривалих з'єднань, тому короткий час очікування за замовчуванням є розумним.

Я не бачив точної проблеми, яку ви описали (закриття навіть із активністю), але бачу, що з'єднання WebSocket закриваються після 30 секунд бездіяльності. Можливо, що в старих версіях Jetty або в поточній версії з якихось інших причин таймер не скидається за допомогою діяльності WebSocket. Я обіходжу це за допомогою методу setMaxIdleTime на моєму об’єкті BlockingChannelConnector, щоб встановити значення часу очікування на ціле число MAX_VALUE.


2

Я думаю, що цей тайм-аут, який ви відчуваєте, насправді є частиною TCP / IP, і рішення полягає в тому, щоб просто час від часу надсилати порожні повідомлення.


1
привіт дякую .. але це мені не допомагає. Я щойно пробував з одним повідомленням щосекунди, і зв’язок все ще закривається
Дуа Бері,

Девіде, ти можеш це підтвердити? Я розумію, що TCP залишає рішення щодо політики, такі як час очікування простою, аж до програми, ОС та мережевої інфраструктури (TCP намагається бути агностичним щодо політики). Можливо, ви думаєте про підтримку в живих, що представляє собою періодичні повідомлення, щоб переконатися, що зв’язок не помер тихо (що в кінцевому підсумку закінчується та припиняє зв’язок зазвичай через 2 години).
канака

@kanaka Я десь це читав, але не можу насправді зробити це. Я точно знаю, що коли я писав власний сервер websocket за допомогою Python, я виявив, що мені потрібно час від часу відправляти пусте повідомлення, щоб запобігти його від’єднанню.
Девід Грейсон,

Це не є частиною TCP / IP, але може бути результатом втрати стану з'єднання через брандмауер, що перебуває у стані, оскільки він занадто довго не працював. Ймовірно, ви думаєте про TCP Keepalives, які вирішують цю проблему.
David Hoelzer

2

Ось приклад того, як налаштувати час очікування веб-сокета Jetty (найімовірніший винуватець) за допомогою WebSocketServlet (у масштабі, вибачте, але синтаксис майже однаковий).

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

1

У мене подібний досвід, і я вважаю, що це може бути браузер, який скорочує сеанс. Я також встановив maxIdleTimeout, але сеанс відмовляється незалежно. Для мене здається, що саме клієнт (браузер) виконує тайм-аут сеансу, а потім кладе трубку.

Не знаю, як це обійти.


1

Оскільки @Doua Beri відчуває близьке з’єднання, навіть коли відправляється 1 Гц, це може бути пов’язано з обмеженнями розміру повідомлень.

Цей уривок із Веб- сокетів Spring може бути корисним, з моїм акцентом ...

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


0

Те саме питання: Використовував бібліотеку WebSockets & sockjs-client / 1.0.3 / sockjs з @ServerEndPoint на стороні сервера Java. З'єднання веб-сокета постійно розривалися.

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

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

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

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

0

Це спрацювало для мене, тоді як інші рішення - ні!

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

Це припиняє потребувати постійного підключення до вашого екземпляра EC2. Тому навіть якщо ви втратите зв’язок через втрату з’єднання з Інтернетом, щоразу, коли ви отримуєте новий доступ до Wi-Fi, він автоматично підключається до активно працюючого ядра.

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

Сподіваюся, це допомагає!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.