Главная страница / Блог / Websocket: интерактивное будущее
сентябрь 28 2016

Websocket: интерактивное будущее

celsoft 28 сентября 2016 Блог 4 963
Websocket: интерактивное будущее
В этом посте мы продолжаем серию публикаций о взаимодействии клиентской и серверной части сайта\веб-приложения.

Если AJAX использует, наверное, каждый профессиональный девелопер, то о websocket многие разработчики знают только понаслышке. В чем же основные «узкое место» AJAX? А в том, что обмен данными может происходить только по инициативе клиента. Ведь AJAX – это самый обычный клиент-серверный HTTP-запрос, который, исходя из самой идеологии HTTP, не может происходить иначе как по «желанию» клиента.

Приведем простой и понятный пример. Предположим, что мы хотим, чтобы наша страница подгружала актуальные новости, которые могли появится за время нахождения пользователя на ней. Чтобы реализовать данный функционал, мы должны с определенной периодичностью запрашивать новости у сервера. С этой целью на клиенте выполняется подобный javascript-код:

function getNews() {
//гипотетическая функция, возвращающая Id последней новости
var last = getLastId();
$.ajax({
    type: "POST",
    url: "/getLastnews",
    data: JSON.stringify({"action" : "getLastnews", "lastId" : last}),
    contentType: "application/json; charset=utf-8",
    success: function(data) {
    	//обработка пришедших от сервера данных
	}
});
}
setInterval(getNews(), 5000);

В этом куске кода, клиент сообщает серверу id последней имеющейся у него новости и запрашивает обновление новостей каждые 5 секунд (5000 миллисекунд). Нетрудно догадаться, что большая часть таких запросов проходит «в холостую», а взаимодействие выглядит примерно так:

Клиент: «дай мне последние новости»
Сервер: «новых новостей нет»
Клиент: «дай мне последние новости»
Сервер: «новых новостей нет»
Клиент: «дай мне последние новости»
Сервер: «есть обновление новостей!»
--передача новостей
--вывод новостей
Клиент: «дай мне последние новости
Сервер: «нет новых новостей»



При использовании AJAX (да и вообще HTTP) у многих разработчиков возникал закономерный вопрос: «а почему бы не отправлять данные от сервера к клиенту именно в тот момент, когда это действительно необходимо, то есть тогда, когда эти данные возникли».

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

Сама идеология HTTP предполагает только взаимодействие по схеме «запрос-ответ». Собственно, именно исходя из этой схемы и строится само определение «клиента» и «сервера». «Клиент – тот, кто запрашивает данные, сервер – тот, кто отвечает». Именно для преодоления этого ограничения и был создан протокол WebSocket.

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

Иначе говоря, обмен данными по WebSocket может быть осуществлен как по инициативе клиента, так и по инициативе сервера. Становится возможным передача информации от сервера клиенту именно в тот момент, когда эта передача требуется.

В настоящий момент, WebSocket де-юре еще не является абсолютным стандартном веба и находится на финальной стадии разработки. Однако, его тестовая реализация уже сегодня включена во все современные браузеры и, если вы не хотите отстать от жизни, интересоваться им следует уже сегодня. Классы и модули для websocket имеются для всех популярных серверных сред разработки (PHP, NodeJS, Python).

Как же выглядит обмен данными по вебсокет?

Перед началом обмена клиент (браузер) отправляет на сервер HTTP-запрос со следующими заголовками:

GET /getLastnews HTTP/1.1
Host: somehost.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Protocol: chat, superchat
Origin: http://somehost.com
Sec-WebSocket-Version: 13

Первые два заголовка не представляют особого интереса: это стандартные заголовки протокола HTTP. Именно в третьем заголовке клиент «предлагает» серверу перейти на вебсокет. Заголовок Sec-WebSocket-Key содержит особый ключ соединения, особым образом обработанный хэш которого передается сервером в ответе. В заголовке Sec-WebSocket-Protocol клиент уведомляет сервер о тех реализациях протокола, которые он поддерживают (интересующихся нюансами подпротоколов мы отошлем к документации WebSocket). По сути данный заголовок чем-то напоминает HTTP-заголовок Content-type.

Ответ сервера, поддерживающего вебсокет выглядит примерно следующим образом:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat

В заголовке Sec-WebSocket-Protocol север сообщает выбранную им реализацию протокола, заголовок Sec-WebSocket-Accept содержит хэш ключа, отправленного клиентом.

После обмена «любезностями» передача данных в HTTP подобном виде прекращается, и общение полностью переходит на WebSocket.

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

Первым делом необходимо создать объект socket, содержащий методы для работы с протоколом, передав конструктору в качестве аргумента адрес нашего сервера. Обратите внимание, что адрес сервера начинается с ws:// (вместо привычного http://) что лишний раз напоминает нам о том, что мы имеет дело с принципиально иным протоколом. Кстати, точно также, как и в случае HTTP(S) у WebSocket существует нешифрованная (ws://) и шифрованная (wss://) реализация.

var socket = new WebSocket("ws://somehost.ru/getLastnews");

У созданного нами объекта socket есть четыре события:
onopen – соединение открыто
onclose – соединение закрыто
onmessage – поступили новые данные
onerror – ошибка

Давайте же установим обработчики для данных событий, задав для каждого из них свой колбэк:

socket.onopen = function() {
console.log("WebSocket соединение успешно открыто");
};

//в качестве аргумента колбэку закрытия соединения передается объект, содержащий информацию о состоянии закрытого соединения
socket.onclose = function(event) {
 	if (!event.wasClean) {
// свойство wasClean принимает значение true если соединение закрыто нормально и false, если соединение закрыто с ошибкой
		console.log(“Соединение закрыто c ошибкой”);
  	} else {
 console.log(“Соединение закрыто нормально”);

 	 }
};

socket.onmessage = function(event) {
  	console.log(“Пришли данные:” + event.data);
//обработка пришедших данных. Данные передаются гипотетической функции showNews()
	showNews(event.data);
};

socket.onerror = function(error) {
  	console.log(error.message);
};

Для отправки данных на сервер мы можем использовать метод .send():

socket.send(“Некоторые данные”);

Как мы видим, в отличие от подхода AJAX, нам нет необходимости проверять наличие новостей через определенные интервалы времени, данные сами придут к нам по инициативе сервера и именно в тот момент будет вызвана функция-обработчик onmessage. После инициализации вебсокет мы имеем полноценное, двухстороннее соединение, которое держится открытым до тех пор пока пользователь не закроет страничку (или не произойдет ошибка или соединение не будет закрыто по инициативе сервера).

Если интересна тема организации веб-сокет сервера, пишите в комментариях. Будем рады раскрыть, рассказать smiley

Прочитав пост, Вы могли бы задать себе закономерный вопрос, если это такая отличная технология, почему же она до сих пор не используется повсеместно? Причин, как всегда, несколько, и причины эти, как всегда, традиционны:

  1. Вебсокет не поддерживается древними версиями браузеров (вроде IE8, которым, к большой печали всех веб-разработчиков мира все еще кто-то пользуется)
  2. Вебсокетом владеет не такое большое число разработчиков, протокол тестовый, статей и обучающих материалов по реализации сервера на вебсокет даже в англоязычном сегменте Интернета не так много
  3. Вебсокет проблематично реализовать на простом виртуальном шаровом хостинге, для его полноценного безкостыльного использования требуется VDS (VPS). Хостеры могли бы устанавливать современное программное обеспечение на свои сервера, но они этого делать не торопятся
  4. Из-за указанных выше причин, популярные CMS (включая вашу любимую DLE) пока не торопятся внедрять вебсокет в свои релизы (90% наших клиентов используют шаровый хостинг который по умолчанию не готов к вебсокет)

Однако, сейчас уже вряд ли вызывает сомнения тот факт, что со временем эта технология будет распространятся. Уже сейчас многие современные порталы и ресурсы любят и используют вебсокет. Ведь это очень, очень , очень удобно smiley

На этом пока все. Удачи вам и хорошего настроения. Подписывайтесь на нашу страницу в социальной сети "Вконтаке" https://vk.com/dlepage

Комментарии

  1. russ-post (Клиенты)

    28 сентября 2016 21:13 30 комментариев
    Мне кажется такая технология совершенно не нужная вещь на сайтах новостных тематик, другое дело социальные сети... Поэтому внедрение этой технологии в DLE вообще нет ни какой, архиважной, необходимостью.
  2. fanaticus (Посетители)

    13 октября 2016 10:33 7 комментариев
    Внедрите PDO, MySQLi скоро уйдет в небытие в след за MySQL

Информация

Комментирование публикаций доступно только пользователям имеющим действующую лицензию на скрипт. Если вы уже приобретали скрипт, то вам необходимо зайти на сайт под своим клиентским аккаунтом.

Календарь

«    Апрель 2024    »
ПнВтСрЧтПтСбВс
1234567
891011121314
15161718192021
22232425262728
2930 

Опрос на сайте

Совершаете ли вы покупки в интернет?