Всем привет, дорогие хабрахабровцы! Недавно я начал изучать node.js и дошёл до самого интересного, а именно — Socket.Io. Поизучав информацию в интернете, я так и не смог найти подробного «гайда» по данному модулю, поэтому пришлось копать самому. Некоторые скажут, что можно и самому понять, что написано на сайте модуля, но некоторым этого будет не достаточно чтобы понять базу web-socket'ов, поэтому я решил написать эту статью для таких людей, а именно на самом 'чётком' примере — чате.
Установка модуля
Итак, давайте приступать?! Для начала нам нужно собственно установить наш Socket.Io, как его установить можете прочитать здесь, а для тех, кто не понял, поясню: есть клиент и сервер, на сервер нужно поставить сам модуль через npm в папку проекта (для этого надо заранее открыть её в консоли, а дальше устанавливать):
npm install socket.io
После того как установили модуль, в папке с проектом (куда ставили) появится папка «node-modules»
Теперь мы должны установить сам .js файл модуля в папку с проектом (.js файл будет использоваться на клиенте), ставить отсюда => *тык*. Вы скачаете архив, и оттуда вы должны достать файл «socket.io.js» и перекинуть в папку с проектом.
Для тех кто не понял, структура папки проекта с чатом должна быть такова на данный момент:
chat: (Сама папка) |node-modules |--socket.io (Внутри <i>node-modules</i>) |socket.io.js
После того как вы скачали .js файл и установили модуль — можно приступать к следующему этапу.
Установка дополнительных модулей
Вам понадобятся также такие модули как:
1. express # Для создания сервера
2. log4js # Отличный логгер
3. http # Сам http-сервер
express:
npm install express
log4js:
npm install log4js
http:
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 |-<i>main.css</i> |-main.js |chat.js
Дальше делаем такой «финт» который будет отправлять клиенту содержимое этой папки при подключении:
chat.js:
app.use(express.static(__dirname + '/public')); // Отправляет "статические" файлы из папки public при коннекте // __dirname - путь по которому лежит chat.js
Отлично, теперь при подключении на localhost:3000 (при запущенном скрипте) у нас будет открываться «index.html», только страница будет пустая из-за того что у нас «index.html» пустой :)
Накидаем эскиз чата в «index.html» (без стилей). Можете просто копировать код в «index.html»
<html>
<head>
<meta charset="utf-8">
<title>chat</title>
<script src="socket.io.js"></script>
<script src="https://code.jquery.com/jquery-3.1.0.min.js" charset="utf-8"></script>
<script src="main.js" charset="utf-8"></script>
<!-- Здесь можете подключить ваш main.css -->
</head>
<body>
<textarea name="name" rows="8" cols="40"></textarea>
<p></p>
<input type="text" name="text" size="20">
<button type="button" name="button">Отправить</button>
</body>
</html>
Прекрасно! Теперь если мы запустим скрипт и откроем 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 мы увидим встречный текст в поле с нашим ником! Прекрасно? Я знаю ^^ Но согласитесь, это еще не чат. Теперь нам надо сделать так, чтобы при нажатии на кнопку «Отправить» <= index.html отправлялся текст на сервер. Для этого дописываем в «main.js» обработчик на кнопку 'button' через jQuery.
$(document).on('click', 'button', function(){ // Прослушка кнопки на клик
var message = $('input').val(); // Все что в поле для ввода записываем в переменную
socket.emit('message', message); // Отправляем событие 'message' на сервер c самим текстом (message)- как переменная
$('input').val(null); // Заполняем поле для ввода 'пустотой'
});
После этого мы можем спокойно делать обработчик события 'message' на самом сервере.
chat.js:
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', сейчас мы будем на клиенте делать обработчик этого события…
main.js:
socket.on('messageToClients', function(msg, name){
console.log(name + ' | => ' + msg); // Логгирование в консоль браузера
$('textarea').val($('textarea').val() + name + ' : '+ msg +'n'); // Добавляем в поле для текста сообщение типа (Ник : текст)
});
Наш чат готов! Теперь вы можете его модернизировать как угодно.
Этот пост был создан потому, что топики, которые на Хабре по созданию чата, были запощены 5 лет назад, а за это время много чего произошло и я решил создать свой топик ) Тем не менее, вот топик, по которому я вдохновлялся — ссылочка. Может я где-то ошибся, поправляйте! Все люди ошибаются.
Спасибо всем за внимание!
Автор: gabcode