В большинстве случаев функции веб-сайта не синхронизируются между пользователями; разные пользователи, заходящие на сайт в разное время, будут видеть разные вещи. Например, если вы вводите данные для входа в систему, ваш собеседник не увидит ее внезапно, как призрак, на своем экране. Однако для многих простых случаев использования синхронизация необходима - например, для форумов или кнопок счетчика посетителей. Все пользователи на одной странице должны видеть (некоторые) одни и те же вещи, и эти вещи должны обновляться в «реальном времени». Как это произошло?

Проблема с HTTP

Если вы немного знакомы с HTTP, вы, вероятно, знаете, что для того, чтобы пользователь увидел что-то на странице, его клиент (например, браузер) должен сделать запрос к серверу этой страницы; это называется «опрос сервера». Если десятки или сотни клиентов опрашивают один сервер, например, в чате, и одновременно отправляют ему POST-запросы, легко увидеть, насколько сложно поддерживать синхронизацию взаимодействия с пользователем.

Поскольку HTTP - это протокол, управляемый клиентом, на самом деле есть только два способа сделать это: короткий опрос и длинный опрос. Как следует из их названий, первый полагается на постоянную отправку запросов GET на сервер, так что клиент всегда обновляется, в то время как второй открывает соединение между клиентом и сервером и делает запрос, но сервер не отвечает, пока что-то не изменится или не истечет время соединения (обычно от 20 до 30 секунд, так как TCP-соединения недолговечны). Это резко снижает количество запросов и ответов, которые должны сделать клиент и сервер соответственно.

Тем не менее, все еще существует лучший метод - включить двустороннюю связь между клиентом и сервером. Это то, что делает Websockets. Клиент и сервер могут передавать информацию друг другу через открытое соединение. Ниже мы увидим, как это работает в node.js.

Реализация веб-сокета с помощью sockets.io

Sockets.io - это модуль, доступный в диспетчере пакетов узлов, поэтому вы должны потребовать его. Ниже представлена ​​типичная установка с использованием Express. Вы можете найти этот код в высокоуровневом файле, таком как bin / www или app.js.

По сути, этот код соединяет компоненты. Модуль http является ядром; запуская на нем метод .createServer(), мы создаем базовый объект server, который может прослушивать конечные точки. Он реагирует на каждый запрос одним обратным вызовом, который предоставляется при создании - в данном случае это наше приложение Express.

Каждый запрос будет обрабатываться с помощью функций Express, некоторые из которых мы кодируем, а некоторые из них поставляются вместе с Express. Модуль сокетов получает объект сервера, так что любой код, который мы присоединяем к объекту «io», имеет доступ к нашему серверу (и может, например, отправлять ему события).

Наконец, если клиент делает запрос к маршруту /socket.io («виртуальный» маршрут, определенный в этом коде, не имеющий параллелей в файловой системе), он перенаправляется с использованием промежуточного ПО промежуточного уровня в файл в файловой системе, который содержит внешняя реализация sockets.io (файл просто прикрепляется к виртуальному маршруту, который можно назначить, добавив /socket.io/socket.io.js к URL-адресу домашней страницы и посмотрев, что появится). В заголовок нашего HTML-файла мы загружаем несколько скриптов, один из которых запрашивает этот маршрут,

Это все, что касается базовой настройки. Теперь нам нужно реализовать соединение через веб-сокеты. Это делается на стороне сервера путем присоединения слушателя «соединения» к объекту io, который мы создали выше. Событие «соединение» инициируется клиентским кодом, который получает домашний адрес нашего сайта и обертывает его для создания клиентского объекта. Затем этот код инициирует событие соединения на io и передает с ним только что упомянутый клиентский объект,

На стороне сервера прослушиватель соединения перехватывает это событие и получает клиентский объект в своем обратном вызове, что позволяет нам устанавливать для него слушателей или передавать ему события. Рождается связь.

Теперь мы можем включить связь клиент-сервер. Присоединяя слушатели и эмиттеры к объекту socket во внешнем коде, мы можем определить, какие события мы хотим, чтобы клиент слушал, и какие события мы хотим, чтобы он отправлял на сервер. И наоборот, для объекта «клиент» во внутреннем коде,

Это почти все, но внимательный читатель заметит несоответствие (это просто то, что любят говорить писатели). Мы начали эту публикацию с обсуждения обновлений «в реальном времени» для всех клиентов, подключающихся к серверу, но, хотя наш код, безусловно, обеспечивает двустороннюю связь между одним клиентом и одним сервером, он определенно не позволяет использовать его для все клиенты сразу.

Предположим, мы создаем форум, и наш клиент инициировал событие submit_post; сервер отреагирует на это событие, обновит свои сохраненные сообщения, а затем… что? Никакие другие клиенты, подключенные к серверу, не будут уведомлены об изменении. Нам нужен способ отправки событий всем клиентам, и мы можем сделать это на стороне сервера, используя io напрямую:

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

Что-нибудь.

Пусть ваши амбиции разыграются, молодой падаван.

Дополнительные вкусности

Поскольку io.on(“connection”, …) - это просто прослушиватель, который не создает соединение, вы можете поместить его в любом месте своего кода столько раз, сколько вам нужно, при условии, что объект io уже сохранен в памяти. Вы должны только * инициировать * новое соединение, однако, один раз; то есть io.connect(…) следует вызывать только один раз в вашем клиентском коде.