NodeJs и Socket.IO
Есть сервер nginx, на котором крутится сайт. Понадобилось в одном из приложений использовать websockets. Установил на этот же сервер NodeJS, добавил к нему express, socket.io. Структура каталогов:
/-папки -php файлы -папка socket.io -/static/js/node/server.js
Файл server.js
var express = require('express'), http = require('http'), path = require('path'); var app = express(); var cookieParser = require('cookie-parser'); var server = app.listen(1337); var io = require('socket.io').listen(server); app.use(cookieParser); io.on('connection', function(client)< client.on('message', function(message)< console.log(message) >); client.on('disconnect', function()< console.log('disconnected'); >); >);
На клиенте

вместо x.x.x.x — естественно реальный ip На выходе получаем: А в консоли браузера: WebSocket connection to ‘ws://x.x.x.x/socket.io/?EIO=2&transport=websocket’ failed: Error during WebSocket handshake: Unexpected response code: 200 Если подключение делать так:
var socket = io.connect();

То в консоли чисто, транспорт идет polling при чем по несколько соединений в секунду и в response мы получаем содержимое папки socket.io Раньше с сокетами и вообще с nodejs дело не имел, потому мне как-то трудно это дается. Может кто подскажет где и что надо подправить?
Создание приложения чата Node.js с помощью Socket.IO в Облачной службе Azure (классическая)
Socket.IO теперь изначально поддерживается в Azure. Масштабирование приложения Socket.IO для работы с тысячами подключений часто разочаровывает. Теперь, когда Azure изначально поддерживает Socket.IO, вы можете разрешить Azure управлять масштабируемостью и доступностью. Узнайте больше о том, как получить любое приложение Socket.IO, работающее в Azure, с помощью нескольких строк кода.
Облачные службы (классическая версия) объявлены устаревшими для новых клиентов. Их поддержка будет полностью прекращена 31 августа 2024 года. Для новых развертываний следует использовать Облачные службы Azure с расширенной поддержкой . Это новая модель развертывания на основе Azure Resource Manager.
Socket.IO обеспечивает связь в режиме реального времени между клиентами и сервером Node.js. В этом руководстве описано, как разместить приложения чата на основе Socket.IO в Azure. См. дополнительные сведения о socket.io.
Снимок экрана завершенного приложения приведен ниже:
! [Окно браузера, отображающее службу, размещенную в Azure] [completed-app]
Предварительные требования
Убедитесь, что следующие продукты и версии установлены для успешного завершения примера, описанного в этой статье.
- установить Visual Studio;
- Установите Node.js
- Установите Python версии 2.7.10
Создание проекта облачной службы
Ниже описаны действия, в результате которых создается проект облачной службы, в которой будет размещаться приложение Socket.IO.

- В меню Пуск или на начальном экране найдите Windows PowerShell. Щелкните правой кнопкой мыши Windows PowerShell и выберите Запуск от имени администратора.
- Сначала создайте каталог c:\node.
PS C:\> md node
PS C:\> cd node
PS C:\node> New-AzureServiceProject chatapp PS C:\Node> Add-AzureNodeWorkerRole

Вы увидите следующий ответ:
Загрузка примера разговора
Для этого проекта мы будем использовать пример чата из [Socket.IO репозитория GitHub]. Выполните следующие действия, чтобы скачать пример и добавить его в ранее созданный проект.
- Создайте локальную копию репозитория с помощью кнопки Клонировать . Можно также загрузить проект при помощи кнопки ZIP .

- Перемещайтесь по структуре каталога локального репозитория, пока не доберетесь до каталога examples\chat. Скопируйте содержимое этого каталога в ранее созданный каталог C:\node\chatapp\WorkerRole1.
На представленном выше снимке экрана выделены файлы, скопированные из каталога examples\chat. - Удалите из каталога C:\node\chatapp\WorkerRole1 файл server.js и переименуйте файл app.js в server.js. При этом файл по умолчанию server.js, созданный ранее с помощью командлета Add-AzureNodeWorkerRole, удаляется и заменяется файлом приложения из примера разговора.
Изменение Server.js и установка модулей
Прежде чем тестировать приложение в эмуляторе Azure, необходимо внести небольшие изменения. Выполните следующие действия над файлом server.js:
- Откройте файл server.js в Visual Studio или в любом текстовом редакторе.
- Найдите раздел Зависимости модуля в начале файла server.js и измените строку sio = require(‘..//..//lib//socket.io’) на sio = require(‘socket.io’), как показано ниже.
var express = require('express') , stylus = require('stylus') , nib = require('nib') //, sio = require('..//..//lib//socket.io'); //Original , sio = require('socket.io'); //Updated var port = process.env.PORT || 3000; //Updated
//app.listen(3000, function () < //Original app.listen(process.env.port, function () < //Updated var addr = app.address(); console.log(' app listening on http://' + addr.address + ':' + addr.port); >);
Сохранив изменения в server.js, выполните следующие действия, чтобы установить необходимые модули, а затем проверьте приложение в эмуляторе Azure:
-
Используя Azure PowerShell, перейдите в каталог C:\node\chatapp\WorkerRole1 и выполните следующую команду для установки необходимых приложению модулей:
PS C:\node\chatapp\WorkerRole1> npm install

Будет выполнена установка модулей, перечисленных в файле package.json. После выполнения команды должен появиться результат, аналогичный приведенному ниже:
Поскольку этот пример изначально был частью репозитория GitHub Socket.IO и через относительный путь ссылался непосредственно на библиотеку Socket.IO, модуль Socket.IO не указан в файле package.json, поэтому его необходимо установить, выполнив следующую команду:
PS C:\node\chatapp\WorkerRole1> npm install socket.io --save
Тестирование и развертывание
- Запустите эмулятор, выполнив следующую команду:
PS C:\node\chatapp\WorkerRole1> Start-AzureEmulator -Launch
Примечание С запуском эмулятора может возникнуть проблема, например во время выполнения команды Start-AzureEmulator произошла непредвиденная ошибка. Подробные сведения: произошла непредвиденная ошибка. Коммуникационный объект System.ServiceModel.Channels.ServiceChannel нельзя использовать для связи, так как он находится в состоянии Faulted. Переустановите AzureAuthoringTools версии 2.7.1 и AzureComputeEmulator версии 2.7 (убедитесь, что версии совпадают).

PS C:\node\chatapp\WorkerRole1> Stop-AzureEmulator
PS C:\node\chatapp\WorkerRole1> Publish-AzureServiceProject -ServiceName mychatapp -Location "East US" -Launch
Важно! Обязательно используйте уникальное имя, иначе произойдет сбой в процессе публикации. После завершения развертывания откроется браузер с переходом к развернутой службе. Если появляется сообщение о том, что предоставленного названия подписки в импортированном профиле публикации нет, то перед развертыванием в Azurе необходимо загрузить и импортировать профиль публикации для вашей подписки. См. раздел Развертывание приложения в Azure в статье Построение и развертывание приложения Node.js в облачной службе Azure.
! [Окно браузера, отображающее службу, размещенную в Azure] [completed-app]
Примечание Если появляется сообщение о том, что предоставленного названия подписки в импортированном профиле публикации нет, то перед развертыванием в Azurе необходимо загрузить и импортировать профиль публикации для вашей подписки. См. раздел Развертывание приложения в Azure в статье Построение и развертывание приложения Node.js в облачной службе Azure.
Теперь ваше приложение выполняется на платформе Azure и может передавать сообщения чата между различными клиентами с использованием Socket.IO.
Чтобы упростить процесс, в этом примере мы ограничили разговор пользователями, подключенными к одному экземпляру. Это означает, что если облачная служба создает два экземпляра рабочей роли, пользователи смогут общаться только с другими пользователями, подключенными к тому же экземпляру рабочей роли. Чтобы масштабировать приложение для работы с несколькими экземплярами роли, можно использовать технологию Service Bus, которая позволяет передавать состояние хранилища Socket.IO между несколькими экземплярами. Примеры см.репозитории пакета Azure SDK для Node.js на GitHub в примерах использования очередей и разделов служебной шины.
Дальнейшие действия
В этом учебнике было рассмотрено создание базового приложения для разговора, размещаемого в облачной службе Azure. Чтобы узнать, как разместить это приложение на веб-сайте Azure, см. статью Создание приложения для разговора Node.js с Socket.IO на веб-сайте Azure.
Дополнительные сведения см. также в центре по разработке для Node.js.
Создаем чат на Node.js и Socket.IO
В данной статье я попытаюсь показать, как можно создать простой чат, используя Node.js в связке с Socket.IO. Изначально я хотел построить чат на чистых Websockets, но столкнулся с практически полным отсутствием готовых реализаций сервера для них в Интернете. Так что решил не изобретать велосипед, а использовать готовую библиотеку.
В моем случае сервер работает под Ubuntu, поэтому все примеры будут для неё (и ссылки в примерах — на него же).
Установка компонентов
Первым делом нам потребуются собственно Node.js (инструкция по инсталляции и ссылки на скачивание здесь) и Socket.IO. Модули для Node.js проще всего устанавливать, используя менеджер npm —
curl http://npmjs.org/install.sh | sh npm install socket.io
Серверная часть
Структура серверной части такова: сервер принимает сообщение, если это команда — выполняет определенные действия, если просто сообщение — рассылает всем остальным участникам.
// Подключаем модуль и ставим на прослушивание 8080-порта - 80й обычно занят под http-сервер var io = require('socket.io').listen(8080); // Отключаем вывод полного лога - пригодится в production'е io.set('log level', 1); // Навешиваем обработчик на подключение нового клиента io.sockets.on('connection', function (socket) < // Т.к. чат простой - в качестве ников пока используем первые 5 символов от ID сокета var 5); var time = (new Date).toLocaleTimeString(); // Посылаем клиенту сообщение о том, что он успешно подключился и его имя socket.json.send(); // Посылаем всем остальным пользователям, что подключился новый клиент и его имя socket.broadcast.json.send(); // Навешиваем обработчик на входящее сообщение socket.on('message', function (msg) < var time = (new Date).toLocaleTimeString(); // Уведомляем клиента, что его сообщение успешно дошло до сервера socket.json.send(); // Отсылаем сообщение остальным участникам чата socket.broadcast.json.send() >); // При отключении клиента - уведомляем остальных socket.on('disconnect', function() < var time = (new Date).toLocaleTimeString(); io.sockets.json.send(); >); >);
В данном коде (и немного больше):
io.sockets — выбор всех подключенных клиентов
io.sockets.sockets[ID] — выбор конкретно взятого клиента с id ID
socket — выбор «текущего» клиента
socket.send(TEXT) — «базовое» событие, отправка сообщения TEXT
socket.json.send(<>) — отправка сообщения в формате JSON
socket.broadcast.send — отправка сообщения всем клиентам, кроме текущего
socket.emit(EVENT, JSON) — отправка пользовательского события EVENT с данными JSON (например — socket.emit(‘whereami’, )), может использоваться для переписывания стандартных событий ‘connected’, ‘message’ и ‘disconnect’.
socket.on(EVENT, CALLBACK) — вызов функции CALLBACK при возникновении события EVENT (например — socket.on(‘whereami’, function(loc)< console.log('I\'m in ' + loc + '!'); >))
Я передаю клиентам сообщения в JSON, т.к. сам текст сообщения автоматически генерируется в клиенте. Таким образом представление данных не зависит от сервера и его легко изменить, не прикасаясь к нему (например, изменить язык); к тому же передается меньший обьем данных между сервером и клиентом.
Клиентская часть
HTML и CSS
#log < width: 590px; height: 290px; border: 1px solid rgb(192, 192, 192); padding: 5px; margin-bottom: 5px; font: 11pt 'Palatino Linotype'; overflow: auto; >#input < width: 550px; >#send < width: 50px; >.in < color: rgb(0, 0, 0); >.out < color: rgb(0, 0, 0); >.time < color: rgb(144, 144, 144); font: 10pt 'Courier New'; >.system < color: rgb(165, 42, 42); >.user
Javascript
socket.io.js автоматически отдается Node.js по адресу nodeJsIp[:port]/socket.io/socket.io.js — ничего дополнительно делать не надо.
client.js
// Создаем текст сообщений для событий strings = < 'connected': '[sys][time]%time%[/time]: Вы успешно соединились к сервером как [user]%name%[/user].[/sys]', 'userJoined': '[sys][time]%time%[/time]: Пользователь [user]%name%[/user] присоединился к чату.[/sys]', 'messageSent': '[out][time]%time%[/time]: [user]%name%[/user]: %text%[/out]', 'messageReceived': '[in][time]%time%[/time]: [user]%name%[/user]: %text%[/in]', 'userSplit': '[sys][time]%time%[/time]: Пользователь [user]%name%[/user] покинул чат.[/sys]' >; window.onload = function() < // Создаем соединение с сервером; websockets почему-то в Хроме не работают, используем xhr if (navigator.userAgent.toLowerCase().indexOf('chrome') != -1) < socket = io.connect('http://46.182.31.65:8080', ); > else < socket = io.connect('http://46.182.31.65:8080'); >socket.on('connect', function () < socket.on('message', function (msg) < // Добавляем в лог сообщение, заменив время, имя и текст на полученные document.querySelector('#log').innerHTML += strings[msg.event].replace(/\[([a-z]+)\]/g, '').replace(/\[\/[a-z]+\]/g, '').replace(/\%time\%/, msg.time).replace(/\%name\%/, msg.name).replace(/\%text\%/, unescape(msg.text).replace('', '>')) + '
'; // Прокручиваем лог в конец document.querySelector('#log').scrollTop = document.querySelector('#log').scrollHeight; >); // При нажатии или кнопки отправляем текст document.querySelector('#input').onkeypress = function(e) < if (e.which == '13') < // Отправляем содержимое input'а, закодированное в escape-последовательность socket.send(escape(document.querySelector('#input').value)); // Очищаем input document.querySelector('#input').value = ''; >>; document.querySelector('#send').onclick = function() < socket.send(escape(document.querySelector('#input').value)); document.querySelector('#input').value = ''; >; >); >;
Наконец, запускаем сервер с логом в файл и в фоновом режиме —
node server.js > output.log &
(стоит отметить, что скрипт у меня запустился только из директории пользователя, куда был поставлен node.js)
Все исходники можно скачать здесь. Сразу говорю, я не гуру программирования и писал для себя, так что на корявость прошу не ругаться (да и бесполезно). Т.к. статику отдает пока апач, желательно запускать у себя на компьютере. Если же лень или неудобно/не можете — живой пример можно посмотреть здесь.
Код протестирован и работает в Opera 11+, Firefox 5+, Chrome 12+. IE9 судя по логам соединяется, получает и отправляет пакеты, но на браузере это не отражается.
В следующем выпуске: записываем историю сообщений, меняем себе имя, пишем в приват другому игроку, и многое другое!
Разработка простого чата на Socket.IO [2016] \ Node.js
Всем привет, дорогие хабрахабровцы! Недавно я начал изучать node.js и дошёл до самого интересного, а именно — Socket.Io. Поизучав информацию в интернете, я так и не смог найти подробного «гайда» по данному модулю, поэтому пришлось копать самому. Некоторые скажут, что можно и самому понять, что написано на сайте модуля, но некоторым этого будет не достаточно чтобы понять базу web-socket’ов, поэтому я решил написать эту статью для таких людей, а именно на самом ‘чётком’ примере — чате.
Установка модуля
Итак, давайте приступать?! Для начала нам нужно собственно установить наш Socket.Io, как его установить можете прочитать здесь, а для тех, кто не понял, поясню: есть клиент и сервер, на сервер нужно поставить сам модуль через npm в папку проекта (для этого надо заранее открыть её в консоли, а дальше устанавливать):
npm install socket.io --save
После того как установили модуль, в папке с проектом (куда ставили) появится папка «node_modules»
Теперь мы должны установить сам .js файл модуля в папку с проектом (.js файл будет использоваться на клиенте), ставить отсюда => *тык*. Вы скачаете архив, и оттуда вы должны достать файл «socket.io.js» и перекинуть в папку с проектом.
Для тех кто не понял, структура папки проекта с чатом должна быть такова на данный момент:
chat: (Сама папка) |node_modules |--socket.io (Внутри node_modules) |socket.io.js
После того как вы скачали .js файл и установили модуль — можно приступать к следующему этапу.
Установка дополнительных модулей
Вам понадобятся также такие модули как:
1. express # Для создания сервера
2. log4js # Отличный логгер
3. http # Сам http-сервер
npm install express --save
npm install log4js
npm install http
После всех этих процедур, папка «node_modules» должна пополниться (*логично вроде*). Теперь можно приступать к разработке нашего чата!
Разработка чата
Теперь мы можем приступать у разработке, но перед этим, надо создать .js-файл в директории проекта «chat.js» в чем мы и будем писать наш чат. Для начала открываем наш chat.js и подключаем все модули таким образом:
var express = require('express'); // Подключаем express var app = express(); var server = require('http').Server(app); // Подключаем http через app var io = require('socket.io')(server); // Подключаем socket.io и указываем на сервер var log4js = require('log4js'); // Подключаем наш логгер var logger = log4js.getLogger(); // Подключаем с модуля log4js сам логгер
Это все что нам нужно подключить в начале. Дальше создаем переменную куда укажем наш порт для прослушивания (для сервера):
var port = 3000; // Можно любой другой порт
После этого можно прологгировать старт скрипта таким образом:
logger.debug('Script has been started. '); // Логгируем.
Дальше ставим на «прослушку» для сервера порт таким образом:
server.listen(port); // Теперь мы можем подключиться к нашему серверу через localhost:3000 при запущенном скрипте
Теперь мы должны сделать так, чтобы клиенту который подключается к нашему серверу «localhost:3000», получал пакет файлов таких как index.html; main.css; socket.io; main.js; чтобы отображалась сама страница с нашим чатом.
Это делается просто, создаем папку «public» в корне проекта, и закидываем туда наш «socket.io.js», а дальше создаем там такие файлы как index.html, main.js, main.css(Не будем пользоваться, это для наглядности). Наша структура проекта должна быть примерно такая:
chat: |node_modules: |-socket.io |-express |-log4js |-http |public: |-index.html |-socket.io.js |-main.css |-main.js |chat.js
Дальше делаем такой «финт» который будет отправлять клиенту содержимое этой папки при подключении:
app.use(express.static(__dirname + '/public')); // Отправляет "статические" файлы из папки public при коннекте // __dirname - путь по которому лежит chat.js
Отлично, теперь при подключении на localhost:3000 (при запущенном скрипте) у нас будет открываться «index.html», только страница будет пустая из-за того что у нас «index.html» пустой 🙂
Накидаем эскиз чата в «index.html» (без стилей). Можете просто копировать код в «index.html»
chat
Прекрасно! Теперь если мы запустим скрипт и откроем localhost:3000, мы увидим наш *кривой* эскиз ) Также вы можете увидеть, что я подключил jQuery, благодаря ему мы будем извлекать текст из поля «удобно».
Как мы можем понять, сейчас наш чат не работает, по сколько не настроены «евенты» в скрипте. Сейчас мы будем всё разбирать. Для начала мы должны подключиться с клиента к серверу (socket.io) в «main.js»
var port = 3000; // Указываем порт на котором у на стоит сокет var socket = io.connect('http://localhost:' + port); // Тут мы объявляем "socket" (дальше мы будем с ним работать) и подключаемся сразу к серверу через порт
Теперь когда мы написали подключение socket.io к серверу через порт, самое время обработать это событие на сервере.
io.connect(port) — Создает событие ‘connection’, нам надо сделать его обработчик на сервере, иначе подключение будет *пустое*, а нам надо еще присвоить никнейм тому кто приконнектился, а это делается в обработчике, просто читаем дальше.
Создаём обработчик в скрипте «chat.js»
io.on('connection', function (socket) < // Создаем обработчик события 'connection' которое создает io.connect(port); с аргументом socket var name = 'U' + (socket.id).toString().substr(1,4); // Создаем никнейм нашему клиенту. В начале буква 'U' дальше берем 3 символа ID (сокета) после первого символа, и все это клеим с помощью '+' socket.broadcast.emit('newUser', name); // Отсылает событие 'newUser' всем подключенным, кроме текущего. На клиенте навешаем обработчик на 'newUser' (Отправляет клиентам событие о подключении нового юзера) socket.emit('userName', name); // Отправляем текущему клиенту событие 'userName' с его ником (name) (Отправляем клиенту его юзернейм) logger.info(name + ' connected to chat!'); // Логгирование >);
Итак, для тех, кто не понял… io.on(‘event’, function(arg)<>) — создаёт прослушку на событие ‘event’ с аргументом arg; передавать аргументы будем чуть позже ) socket.id — ID подключения этого сокета (сокет — клиент), socket.broadcast.emit(‘newUser’, name); — отправка события ‘newUser’ всем кроме текущего сокета, с переменной name (текущего сокета). socket.emit(‘userName’, name); — отправляет событие ‘userName’ только текущему сокету c переменной name.
Для тех, кто не понял — сервер и клиент могут отправлять и принимать события одинаково:
socket.emit(‘event’) — отправляет на сервер\клиент
socket.on — прослушивает события на клиенте
io.on — прослушивает события на сервере
Теперь создаём в «main.js» прослушки на ‘newUser’, ‘userName’…
socket.on('userName', function(userName) < // Создаем прослушку 'userName' и принимаем переменную name в виде аргумента 'userName' console.log('You\'r username is =>' + userName); // Логгирование в консоль браузера $('textarea').val($('textarea').val() + 'You\'r username => ' + userName + '\n'); // Выводим в поле для текста оповещение для подключенного с его ником >); socket.on('newUser', function(userName)< // Думаю тут понятно уже =) console.log('New user has been connected to chat | ' + userName); // Логгирование $('textarea').val($('textarea').val() + userName + ' connected!\n'); // Это событие было отправлено всем кроме только подключенного, по этому мы пишем другим юзерам в поле что 'подключен новый юзер' с его ником >);
$(‘textarea’).val(‘текст’); — изменение текста в текстовом поле. \n — переход на новую строку
Теперь когда мы откроем localhost:3000 мы увидим встречный текст в поле с нашим ником! Прекрасно? Я знаю ^^ Но согласитесь, это еще не чат. Теперь нам надо сделать так, чтобы при нажатии на кнопку «Отправить» отправлялся текст на сервер. Для этого дописываем в «main.js» обработчик на кнопку ‘button’ через jQuery.
$(document).on('click', 'button', function()< // Прослушка кнопки на клик var message = $('input').val(); // Все что в поле для ввода записываем в переменную socket.emit('message', message); // Отправляем событие 'message' на сервер c самим текстом (message)- как переменная $('input').val(null); // Заполняем поле для ввода 'пустотой' >);
После этого мы можем спокойно делать обработчик события ‘message’ на самом сервере.
io.on('connection', function (socket) < var name = 'U' + (socket.id).toString().substr(1,4); socket.broadcast.emit('newUser', name); logger.info(name + ' connected to chat!'); socket.emit('userName', name); // Обработчик ниже // Мы его сделали внутри коннекта socket.on('message', function(msg)< // Обработчик на событие 'message' и аргументом (msg) из переменной message logger.warn('-----------'); // Logging logger.warn('User: ' + name + ' | Message: ' + msg); logger.warn('====>Sending message to other chaters. '); io.sockets.emit('messageToClients', msg, name); // Отправляем всем сокетам событие 'messageToClients' и отправляем туда же два аргумента (текст, имя юзера) >); >);
Отлично! Теперь когда мы будем отправлять текст со страницы, он у нас будет логгироваться в консоли node, так же мы всем клиентам отправили событие ‘messageToClients’, сейчас мы будем на клиенте делать обработчик этого события…
socket.on('messageToClients', function(msg, name) < console.log(name + ' | =>' + msg); // Логгирование в консоль браузера $('textarea').val($('textarea').val() + name + ' : '+ msg +'\n'); // Добавляем в поле для текста сообщение типа (Ник : текст) >);
Наш чат готов! Теперь вы можете его модернизировать как угодно.
Этот пост был создан потому, что топики, которые на Хабре по созданию чата, были запощены 5 лет назад, а за это время много чего произошло и я решил создать свой топик ) Тем не менее, вот топик, по которому я вдохновлялся — ссылочка. Может я где-то ошибся, поправляйте! Все люди ошибаются.
Спасибо всем за внимание!