Разработка простого чата на Socket.IO [2016] – Node.js

в 7:35, , рубрики: javascript, JS, node.js, socket.io, web, чат

Всем привет, дорогие хабрахабровцы! Недавно я начал изучать 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

Источник


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js