сокет — В чем разница между socket’ом и websocket’ом?

Stack Overflow на русском

Loading…

  1. 0
  2. +0
    • Тур Начните с этой страницы, чтобы быстро ознакомиться с сайтом
    • Справка Подробные ответы на любые возможные вопросы
    • Мета Обсудить принципы работы и политику сайта
    • О нас Узнать больше о компании Stack Overflow
    • Бизнес Узнать больше о поиске разработчиков или рекламе на сайте
  3. Войти Регистрация
  4. текущее сообщество

ru.stackoverflow.com

Spring WebSocket. How it works? / Habr

Доброго времени суток уважаемые хабравчане. На моем текущем месте работы было принято решение перевести взаимодействие с web клиентом на WebSocket. Серверная часть написана на Java с использованием фреймворка Spring. В данной статье я хотел поделиться особенностью устройства Spring WebSocket.

WebSocket обеспечивает двустороннюю связь между клиентом и сервером, используя одно TCP соединение.

Протокол состоит из двух фаз:


Для Handshake запроса используется HTTP GET запрос, в результате которого происходит обновление соединения до WebSocket.

В данной статье мы подробно разберем механизм установления связи между клиентом и сервером, прокачкой соединения к WebSocket и пересылкой сообщения в Spring приложении.
В разборе будем использовать Spring-WebSocket и Annotation based конфигурацию.

Создание конфигурационного класса

Итак, для начала нам нужно объявить точку доступа, к которой будет обращаться клиент для создания соединения и отправки данных.

Для использования WebSocket в конфигурационном классе нам необходимо использовать аннотацию @EnableWebSocket. Из описания данной аннотации следует необходимость реализовать интерфейс WebSocketConfigurer нашим конфигурационным классом. Интерфейс WebSocketConfigurer содержит единственный метод registerWebSocketHandlers(WebSocketHandlerRegistry registry). Используя входной параметр WebSocketHandlerRegistry мы осуществляем добавление обработчиков (WebSocketHandler) входящих сообщений на определенный url.

Рассмотрим работу аннотации @EnableWebSocket более подробно.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebSocketConfiguration.class)
public @interface EnableWebSocket {
}

Основная задача данной аннотации — импорт конфигурационного класса DelegatingWebSocketConfiguration, который при помощи @Autowired получит экземпляры интерфейса WebSocketConfigurer (наш конфигурационный класс). Данные экземпляры WebSocketConfigurer используются в родительском классе WebSocketConfigurationSupport для создания бина HandlerMapping.

Создание бина HandlerMapping необходимо чтобы в дальнейшем DispatcherServlet смог определить обработчик для данного url.


Для преобразования WebSocketHandler в экземпляр HandlerMapping нам потребуются адаптеры WebSocketHttpRequestHandler и WebSocketHandlerMapping.

При помощи WebSocketHttpRequestHandler мы произведем приведение WebSocketHandler к HttpRequestHandler. А далее используя связку url, на который мы ждем запроса по открытию WebSocket, и HttpRequestHandler создадим экземпляр WebSocketHandlerMapping, который и будет зарегистрирован в DispatcherServlet для обработки HTTP запроса.


Когда клиент посылает запрос на открытие WebSocket соединения, запрос через DispatcherServlet приходит на метод handleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) нашего декоратора WebSocketHttpRequestHandler.

В данном методе происходит вызов Interceptors, объявленных в конфигурационном классе при задании WebSocketHandlers, и вызов метода doHandshake, дефолтного или пользовательского экземпляра HandshakeHandler.


Обработка Handshake запроса

На работе метода doHandshake остановимся чуть подробнее. Здесь и происходит вся магия преобразования соединения к WebSockets. Но для начала давайте разберемся с параметрами пользовательского запроса и серверного ответа.

Типичный пример пользовательского запроса выглядит следующим образом:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
 Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

  • Origin — содержит url, с которого производится запрос. Используется для верификации допустимых адресов.
  • Sec-WebSocket-Protocol — определяет набор под-протоколов, к примеру, STOMP, который будет рассмотрен в следующих статьях.
  • Sec-WebSocket-Key — случайный ключ, который генерируется браузером: 16 байт в кодировке Base64.
  • Sec-WebSocket-Version — версия протокола.
  • Sec-WebSocket-Extensions — дополнительные расширения, например, permessage-deflate говорит о том, что сообщения будут передавать в сжатом виде.

Типичный ответ от сервера:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Код ответа HTTP 101 говорит об переключении протокола, в нашем случае на WebSocket.
Sec-WebSocket-Accept — рассчитанное значение на основе переданного Sec-WebSocket-Key и константы «258EAFA5-E914-47DA-95CA-C5AB0DC85B11» — по сути это подтверждение от сервера о готовности инициировать WebSocket соединение.

Работу метода doHandshake можно схематично представить в таком виде:


Стратегия обновления запроса до WebSocket

На данный момент доступны стратегии обновления соединения
  • TomcatRequestUpgradeStrategy
  • JettyRequestUpgradeStrategy
  • UndertowRequestUpgradeStrategy
  • GlassFishRequestUpgradeStrategy
  • WebLogicRequestUpgradeStrategy
  • WebSphereRequestUpgradeStrategy

Процесс обновления стратегии состоит из следующих шагов:
* Экземпляр EndPoint создается путем оборачивания WebSocketHandler в StandardWebSocketHandlerAdapter, который и является наследником EndPoint. Для создания сессии используется StandardWebSocketSession.

** Для обновления HttpServletRequest используется стандартный метод данного интерфейса update, в который передаем реализацию HttpUpgradeHandler,
в случае работы с Tomcat это WsHttpUpgradeHandler. При инициализации экземпляра HttpUpgradeHandler происходит создание и регистрация EndPonit в WebSocketContainer.

После данных настроек наша реализация WebSocketHandler готова принимать входящие сообщения, а используя WebSocketSession мы получили возможность отправлять сообщения клиенту.

Спасибо большое за внимание. В следующих статьях рассмотрим работу fallback механизма при помощи SockJS и возможности под-протокола STOMP.

Использованные источники:

→ The WebSocket Protocol
→ Spring WebSocket

habr.com

будущее уже здесь! / Habr

Сегодня я вкратце расскажу о технологии WebSocket, о предпосылках к её появлению, о текущих проблемах и об их решениях.

Предпосылки

С тех пор как проектировалcя протокол HTTP утекло много воды, и прошли те времана когда Javascript использовался лишь для падающих снежинок на фоне. Вскоре появилась потребность дополнительного обмена данными с сервером, для этого придумали AJAX (сначала через теги iframe и script, затем придумали XMLHttpRequest). Однако, все эти способы подразумевают что передача данных должна инициироваться клиентом. Конечно, всем известны чаты на бесконечно загружаемых frame’ах, однако это всё лишь костыли, которые к тому же создавали большую нагрузку на сервер, из-за несовершенства тех инструментов, которые применялись при разработке. Каждый пользователь съедал процесс на сервере под себя.
В связи с вынужденными мерами разработчиков браузеров по обеспечению безопасности, iframe и XMLHttpRequest не позволяют обмениваться данными с доменами, отличными от домена текущего документа. Существует хаки типа XhrIframeProxy, который образует поток данных между документами используя Историю. Однако, всё это шито белыми нитками.
Достаточно хорошим вариантом является long-polling — метод при котором броузер шлет последовательные запросы, и каждый запрос «висит» пока не в него не поступит пакет данных. Однако, внушительным минусом является большой overhead по трафику и кол-ву соединений.
Главным недостатком этих методов является сложность и муторность конечной разработки, которая представляет собой месиво из полезной логики и низкоуровневой лапши. Таким образом, человек не обладающий твердыми знаниями не может без осложнений реализовать передачу данных по инициативе сервера.
Was ist das?

И вот, наступил 2009 год, 23 апреля. Появился черновик документа под названием «The Web Sockets API», который положил начало конца всех бед. В нем был описан объект доступный из Javascript, который обладает следующими особенностями:
— Origin-based cross-domain policy (политикой безопасности основанной на передаче Orgin) — то есть подключиться мы можем с любой страницы к любому серверу, и он уже сам решит исходя из Orgin’а (адреса документа) надо ли ему это счастье.
— Низкий overhead по трафику.
— Возможность используя одно соединение выполнять передачу данных в обе стороны
— На данный момент нативно поддерживается только в Google Chrome 4+ stable и Safari 5, обещано в Mozilla Firefox 3.7 и IE 9.
Какие есть альтернативы для поддержки всех броузеров?

Варианты:

1. Flash-эмулятор (http://github.com/gimite/web-socket-js)
Минусы: код УГ, не у всех есть флеш, у некоторых стоят flashblock-плагины.

2. Использовать iframe (бесконечную загрузку iframe) и long-polling (ожидание-перезапрос,….).
Минусы: Реализовать три различных транспорта на уровне приложения и наладить межпроцессную коммуникацию — весьма нетривиальная задача.

Чип и Дэйл спешат на помощь

Обдумав ситуацию, я решил что нужен фреймворк удовлетворяющий следующим требованиям:
— Абстракция API от разных транспортов (native websocket, flash websocket, comet, long-polling) как на сервере, так и на клиенте.
— Асинхронность: 1 процесс на сервере должен одновременно поддерживать множество соединений с клиентами.
— Javascript-клиент должен автоматически адаптироваться под броузер, наличие Flash, тип соединения пользователя (direct, proxy, и т.д.).

Дело было вечером, делать было нечего.
Пример того что получилось — http://loopback.su/websocket/ (если упадет не обессудьте, стоит под столом дома).
Серверное приложение тут.
Работает во всех броузерах вплоть до IE 6. Серверная реализация — модули к phpDaemon. Всё вместе можно вытянуть с github.
Главным преимуществом данного подхода является то что вам не нужно думать о том какой у клиента броузер, когда вы пишете клиент-серверное приложение, вы просто пишете так как будто WebSocket у всех нативный.
При желании, серверную часть можно переписать и на другие языки программирования.

habr.com