Node.js + Socket.io реализуют мгновенный чат один на один

Node.js
Node.js + Socket.io реализуют мгновенный чат один на один

Для реализации приложения мгновенного чата один на один важным моментом является то, что сообщения могут передаваться в режиме реального времени.Одним из решений является использование известного протокола Websocket.В этой статье мы используем фреймворк Socket.io в Node. .js для реализации.

Предварительный просмотр эффекта

Давайте посмотрим на окончательный эффект, которого мы достигли, а именно:

Вы также можете ввести следующие два URL-адреса в браузере, чтобы испытать:

http://120.27.239.212:30010/?sender=赵敏&receiver=聂小倩
http://120.27.239.212:30010/?sender=聂小倩&receiver=赵敏

Технический отбор

  • Внешний интерфейс: HTML + CSS + JS также использует Boostrap для реализации макета страницы и рендеринга некоторых стилей.
  • Серверная часть: Node.js + Express + Socket.io.

Интерфейсная реализация

Макет HTML-страницы

HTML-разметка страницы чата несложная и примерно разделена на 3 слоя следующим образом:

  • заголовок чата: информация заголовка интерфейса чата.
  • chat-content: используется для отображения общего содержимого чата. То, что вы видите сейчас, это просто пустой div. После отправки или получения информации чата он будет манипулировать DOM, чтобы вставить содержимое сообщения в тело чата.
  • chat-bottom: внизу показано окно ввода контента и кнопка отправки нашего окна чата.
 <div class="container">
   <div class="chat-header row">
    <span class="col-xs-2 chat-header-left glyphicon glyphicon-menu-left"></span>
   	<span class="col-xs-8 chat-header-center" id="chatHeaderCenter"></span>
    <span class="col-xs-2 chat-header-right glyphicon glyphicon-option-horizontal"></span>
  </div>
  <div class="chat-content" id="chatContent"></div>
  <div class="chat-bottom row">
    <span class="col-xs-10 col-md-11 input-text"><input type="text" class="form-control " id="inputText" placeholder="请输入要发送的内容..."></span>
  	<span class="col-xs-2 col-md-1 span-submit">
    	<input class="btn btn-default btn-primary input-submit" id="sendBtn" data-dismiss="alert" type="submit" value="发送">
    </span>
  </div>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="./js/chat.js"></script>

Socket.io Client

Сначала клиент создает объект сокета, и первым параметром io() является URL-адрес связанного сервера, который по умолчанию является window.location.
И у клиента, и у сервера Socket есть две функции on() и emit(), которые также являются основными. Благодаря этим двум функциям можно легко реализовать двустороннюю связь между клиентом и сервером.

  • emit: инициировать событие, первый параметр — это имя события, второй параметр — это данные, которые должны быть отправлены на другой конец, а третий параметр — это функция обратного вызова, используемая для подтверждения получения информации другой стороной, которая может быть игнорируется.
  • on: Зарегистрируйте событие для прослушивания событий, вызванных emit.
// js/chat.js
const socket = io();
socket.on('connect', () => {
  socket.emit('online', query.sender);
});
socket.on('reply_private_chat', replyPrivateMessage);
...

Чтобы отправить сообщение на стороне клиента, нужно прослушать событие onclick или событие возврата каретки кнопки отправки, выполнить некоторую обработку сообщения и отправить его на сервер через socket.emit, а сервер передает его на другой клиент.

Более подробный код front-end части здесь не приводится, вы можете клонировать его на Github, чтобы посмотреть самостоятельно, в конце статьи есть адрес примера кода.

const chatHeaderCenter = document.getElementById('chatHeaderCenter');
const inputText = document.getElementById('inputText');
const sendBtn = document.getElementById('sendBtn');
chatHeaderCenter.innerText = query.receiver;
sendBtn.onclick = sendMsg;
inputText.onkeydown = sendMsgByEnter;

function sendMsg() {
  const value = inputText.value;
  if (!value) return alert('Message is required!');
  const message = { sender: query.sender, receiver: query.receiver, text: value };
  socket.emit('private_chat', message, data => {
    renderMessage(data, true);
  });
  inputText.value = '';
}
...

бэкэнд реализация

Создайте сервис с помощью Express

Используйте Express для создания нашей серверной службы, создайте app.js, который прослушивает порт 30010, и загрузите нашу клиентскую страницу.

// app.js
const express = require('express');
const app = express();
const path = require('path');
const server = require('http').createServer(app);
const PORT = 30010;

app.use(express.static(path.join(__dirname, '../', 'public')));

server.listen(PORT, () => console.log(`Server is listening on ${PORT}`));

Представляем Socket.io

Выше мы построили простой экспресс-сервис, теперь мы представляем наш собственный io.js.

// app.js
require('./io.js')(server);

Создайте io.js и передайте объект сервера при загрузке socket.io. В это время вы получите объект ввода-вывода на стороне сервера и синхронно зарегистрируете событие подключения. Если появится новый клиент, он будет запущен. функции обратного вызова соединения относится к текущему соединению между клиентом и сервером.

Также есть события online, private_chat, разъединения, некоторые из которых предоставляются системой, а некоторые настраиваются нами, которые будут представлены позже.

const _ = require('underscore');
const moment = require('moment');
const userData = require('./users.json');
const USER_STATUS = ['ONLINE', 'OFFLINE'];
const users = {};

module.exports = server => {
  const io = require('socket.io')(server);

  io.on('connection', socket => {
    socket.on('online', ...)
    socket.on('private_chat', ...);
    socket.on('disconnect', ...);
  });
}

Онлайн-уведомление

on('online') - это наше пользовательское событие, которое запускается клиентом после того, как он выходит в сеть, чтобы сообщить нам информацию о пользователе текущего клиента, сохранить socket.id, чтобы установить отношение сопоставления между пользователем и socket.id для последующих приватных чатов. Здесь socket.id будет меняться каждый раз, когда клиент отключает тяжелую цепочку.

socket.on('online', username => {
  socket.username = username;
  users[username] = {
    socketId: socket.id,
    status: USER_STATUS[0]
  };
})

Получать отправленные сообщения в приватном чате

on('private_chat') также является нашим настраиваемым событием. После получения сообщения, отправленного клиентом, сообщение обрабатывается, чтобы определить, находится ли получатель в сети. Если соответствующий сокет найден в сети через socket.id, сообщение отправляется в получатель.Если пользователь Если вы не в сети, вы можете выполнить некоторую автономную обработку push-сообщений. Ключевым моментом переадресации приватного чата здесь является socket.to().emit().

socket.on('private_chat', (params, fn) => {
  const receiver = users[params.receiver];
  params.createTime = moment().format('YYYY-MM-DD HH:mm:ss');
  const senderData = _.findWhere(userData, { username: params.sender });
  params.senderPhoto = (senderData || {}).photo;

  if (!params.senderPhoto) {
    const senderLen = params.sender.length;
    params.senderPhotoNickname = params.sender.substr(senderLen - 2)
  }
  fn(params);
  if (receiver && receiver.status === USER_STATUS[0]) {
    socket.to(users[params.receiver].socketId).emit('reply_private_chat', params);
  } else {
    console.log(`${params.receiver} 不在线`);
    // 可以在做些离线消息推送处理
  }
});

disconnect

Запускается при разрыве соединения. Reason указывает причину, по которой клиент или сервер отключили соединение. В этом случае мы также изменим причину неработающей ссылки.

socket.on('disconnect', reason => {
  if (users[socket.username]) users[socket.username].status = USER_STATUS[1];
});

Код и развертывание

Я упаковал приведенный выше пример как образ Docker.Если вам интересно, вы можете выполнить следующую команду, чтобы вытащить его, развернуть и запустить самостоятельно.

docker pull docker.io/qufei1993/private-chat-socketio

Пример кода:

Демонстрационный онлайн-опыт:

http://120.27.239.212:30010/?sender=赵敏&receiver=聂小倩
http://120.27.239.212:30010/?sender=聂小倩&receiver=赵敏

Суммировать

Socket.io упакован очень хорошо. Использование его для разработки приложения мгновенного чата требует от нас доступа к нашей собственной бизнес-логике. Эта статья — лишь верхушка айсберга системы чата. Нам еще многое предстоит сделать. Заинтересованные друзья добро пожаловать, чтобы обратить внимание, и будет продолжать делиться некоторыми другими функциями в будущем.