Прошелся по мануалу с официального сайта socket.io, воспроизвел шаги, кое-что поправил, так как не заводилось, перевел, делюсь. Картинки брал оттуда же.
Создание чата с помощью традиционного набора LAMP (Linux, Apache, MySQL, PHP) всегда было непростой задачей. Приходилось использовать long polling, для своевременного получения информации, добавлять timestamps, и все это работало не так быстро, как хотелось бы.
Сокеты всегда были наиболее удобным решением для систем реального времени, в том числе и чатов, и позволяли приложениям одновременно обмениваться информацией в обе стороны.
В клиент-серверной архитектуре чата сервер отправляет (push) сообщения клиентам. Когда бы вы не написали сообщение, вы рассчитываете на то, что сервер разошлет его всем подключенным клиентам.
Первой нашей целью будет создание простой HTML страницы, которая представляет пользователю форму ввода и отправленные сообщения. Мы собираемся использовать фреймворк express (NodeJS) для отображения таких страниц. Если у вас еще не установлен NodeJS, установите его.
Теперь, давайте создадим отдельную директорию, в моем случае я назвал её chat-example, и в ней файл-манифест под названием package.json .
В нем будут содержаться следующие строки:
{ "name": "socket-chat-example", "version": "0.0.1", "description": "my first socket.io app", "dependencies": {} }
В дальнейшем, для установки всех зависимостей, которые нам понадобятся, мы будем использовать команду npm install –save
Первым делом установим фреймворк:
npm install --save <a href="mailto:express@4.10.2">express@4.10.2</a>
Теперь, после установки, мы можем создать файл index.js, в котором будет происходить основная жизнь нашего проекта. Его содержимое на данный момент:
var app = require('express')(); var http = require('http').Server(app); app.get('/', function(req, res){ res.send('<h1>Hello world</h1>'); }); http.listen(3000, function(){ console.log('listening on *:3000'); });
Что означает следующее:
app
таким образом, что она становится обработчиком функции, который может быть передан HTTP серверу (строка 2).Если вы запустите node index.js вы должны увидеть следующее:
И, если в этот момент вы откроете сайт (//localhost:3000
), то должны увидеть такую картину:
До сих пор мы использовали res.send в нашем index.js, в котором передавали строку. Такой код станет невыносимо запутанным, если мы поместим туда весь HTML код, который хотим. Гораздо лучше будет создать отдельный файл, например index,html, и работать с ним.
Давайте переработаем наш обработчик роутинга и воспользуемся функцией sendFile (регистр имеет значение).
app.get('/', function(req, res){ res.sendFile(__dirname + '/index.html'); });
А в index.html
мы запишем следующее:
<!doctype html> <html> <head> <title>Socket.IO chat</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font: 13px Helvetica, Arial; } form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; } form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; } form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; } #messages { list-style-type: none; margin: 0; padding: 0; } #messages li { padding: 5px 10px; } #messages li:nth-child(odd) { background: #eee; } </style> </head> <body> <ul id="messages"></ul> <form action=""> <input id="m" autocomplete="off" /><button>Send</button> </form> </body> </html>
Если вы завершите процесс (нажав Control+C и запустив node index.js заново), и обновите страницу, вы должны увидеть такую форму:
Socket.IO состоит из двух частей:
socket.io
socket.io-client
Сейчас, для нужд разработки, серверный socket.io настраивает клиента за нас, так что нам нужно установить всего один модуль:
npm install --save socket.io
После того, как модуль и все его зависимости установятся, давайте изменим index.js: (прим: Я поправил строку 5 на res.sendFile(__dirname + ‘/index.html’); так как в примере на сайте использовалась устаревшая форма. С ней у меня не работало)
var app = require('express')(); var http = require('http').Server(app); var io = require('socket.io')(http); app.get('/', function(req, res){ res.sendFile(__dirname + '/index.html'); }); io.on('connection', function(socket){ console.log('a user connected'); }); http.listen(3000, function(){ console.log('listening on *:3000'); });
Обратите внимание, что я инициализирую новый экземпляр socket.io
передавая объект http
(the HTTP server). После этого я добавляю слушателя для события connection, который будет вызываться при подключении новых входящих сокетов, и писать об этом в лог
.
Теперь давайте добавим сниппет в index.html перед тэгом </body>
:
<script src="/socket.io/socket.io.js"></script> <script> var socket = io(); </script>
Это единственное, что требуется для загрузки клиентской части socket.io, мы создаем глобальную переменную, после чего подключаемся.
Обратите внимание, что я не указываю никакого адреса (URL) когда подключаю библиотеку и вызываю io()
, так как по умолчанию он пытается загрузить библиотеку с того сервера, который вернул ему эту страницу.
Если теперь вы перезапустите сервер вы увидите в консоли надпись
“a user connected”.
Откройте несколько вкладок, и вы увидите несколько записей:
Каждый сокет также генерирует специальное событие disconnect (обратите внимание, функция создается внутри функции-обработчикаconnection)
:
io.on('connection', function(socket){ console.log('a user connected'); socket.on('disconnect', function(){ console.log('user disconnected'); }); });
Теперь, если вы обновите страницу несколько раз, вы увидите, что это работает:
Основная идея, заложенная в Socket.IO состоит в том, что вы можете посылать и получать любые события по вашему выбору, содержащие любые данные, которые вам могут понадобиться. Подойдет любой объект, который может быть преобразован в JSON, а так же поддерживаются бинарные данные.
Давайте добавим следующий функционал: когда пользователь отправляет сообщение, сервер получает событие chat message
. Для этого давайте изменим javascript в нашем index.html
:
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script> <script src="//code.jquery.com/jquery-1.11.1.js"></script> <script> var socket = io(); $('form').submit(function(){ socket.emit('chat message', $('#m').val()); $('#m').val(''); return false; }); </script>
А в index.js
добавим обработчик события chat message
:
io.on('connection', function(socket){ socket.on('chat message', function(msg){ console.log('message: ' + msg); }); });
Теперь, после перезапуска сервера, вы можете отправлять сообщения с веб-формы и читать их в консоли (видео - https://i.cloudup.com/transcoded/zboNrGSsai.mp4).
Следующая наша цель это заставить сервер рассылать сообщения всем подписанным клиентам.
Для такой рассылки Socket.IO предоставляет нам функцию io.emit
:
io.emit('some event', { for: 'everyone' });
Если мы хотим отправить сообщение всем, кроме определенного сокета, вы можете воспользоваться флагом broadcast
:
io.on('connection', function(socket){ socket.broadcast.emit('hi'); });
Но мы, в рамках этого приложения, просто отправим сообщением всем, включая отправителя:
io.on('connection', function(socket){ socket.on('chat message', function(msg){ io.emit('chat message', msg); }); });
А на стороне клиента мы будем отслеживать событие chat message
и, при получении, его содержимое мы добавим на страницу. Окончательный код JavaScript в нашем index,html будет выглядеть так:
<script> var socket = io(); $('form').submit(function(){ socket.emit('chat message', $('#m').val()); $('#m').val(''); return false; }); socket.on('chat message', function(msg){ $('#messages').append($('<li>').text(msg)); }); </script>
И мы получили работающее приложение, уместившись в 20 строк кода!
Видео: https://i.cloudup.com/transcoded/J4xwRU9DRn.mp4