предисловие
Этот проект изначально был учебным проектом, когда я был студентом, чтобы найти работу, но я не ожидал, что ему будет уделено много внимания, и звезда вот-вот сломает К, что также вдохновило меня продолжать его улучшать. С одной стороны, это должно быть достойно людей, уделяющих внимание обучению, с другой стороны, я тоже хочу самосовершенствоваться, потихоньку улучшая проект.
То, что я предлагаю вам сегодня, основано на функции непрочитанных сообщений Websocket+Node+Redis, которая может быть более склонна к реальному направлению боя.Необходимо иметь некоторое представление о Websocket и Node.Конечно, если вы этого не сделаете знайте это, вы также можете увидеть эффект.Ссылка на эффект (www.qiufengh.com/) может пробудить вашу мотивацию к учебе~
Ниже я объясню это своим ходом мыслей.Код может быть не очень объяснен, но основная логика объяснена.На нем также есть адрес github.Если вам интересно,можете просмотреть его подробно. Мои собственные идеи более или менее незрелы, но у меня все еще есть наглость показать свое лицо.Если у вас есть какие-либо предложения, пожалуйста, дайте их больше, чтобы я мог усовершенствовать эту работу.
дизайн
Во-первых, всем знакомо непрочитанное сообщение, которое представляет собой красную точку, появляющуюся во время различных чатов, и это маленькая точка, которую больные обсессивно-компульсивным расстройством должны убрать, как показано на 👇. Я возьму вас для реализации такой функции.
Поскольку метод «один к одному» проще, я сейчас рассматриваю только ситуацию «многие ко многим», то есть непрочитанные сообщения в комнате (также называемой группой, позже названной комнатой), затем разрабатываю такую функцию, Премьер-министр Я разделил его на 3 типа пользователей.
- офлайн-пользователь
- онлайн-пользователь
- Онлайн-пользователи и пользователи, состоящие в группе
офлайн-пользователь
Этот сценарий эквивалентен тому, когда мы выходим из WeChat, но когда кто-то еще отправляет сообщение в комнате, когда мы снова открываем ее, мы все еще можем видеть непрочитанные сообщения, которые выросли в комнате.
онлайн-пользователь
Этот сценарий эквивалентен тому, когда мы остаемся на странице списка чатов.Когда другие отправляют сообщения в комнате, мы можем видеть, что количество непрочитанных сообщений увеличивается в реальном времени.
Пример сценария.
Онлайн-пользователи и пользователи в комнате
Этот сценарий на самом деле довольно распространен. Когда кто-то отправляет новое сообщение, мы можем видеть его в режиме реального времени. В настоящее время нет необходимости отмечать непрочитанные сообщения.
Пример сценария.
блок-схема
Основной процесс можно упростить, разделив его на три части, а именно пользователя, функцию push и очередь сообщений.
Пользователь может быть поставщиком сообщений или получателем сообщений. Далее идет процесс.
Конечно, этот процесс включает в себя хранение относительно сложных сообщений, способы отправки, получения, синхронизации и т. д. Ниже приводится подробное описание этого процесса.
Объяснение процесса на схеме
A. Список пользователей комнаты хранится в кеше узла (информация здесь также может храниться в Redis)
B. Список непрочитанных сообщений, хранящихся в Redis
C. Список непрочитанных сообщений, хранящихся в MongoDB
- Пользователь 1 входит на домашнюю страницу.
- Пользователь 1 входит в комнату, сбрасывает непрочитанные сообщения пользователя в комнате 1 и запускает модуль обновления для обновления списка непрочитанных сообщений пользователя B.
- Пользователь 1 отправляет сообщение в комнату B.
- Серверной части необходимо получить список пользователей комнаты, чтобы определить, находится ли пользователь в комнате?
- Да, поскольку пользователь в комнате прочитал последнее сообщение, подсчет не требуется.
- Нет, если пользователя нет в комнате, обновить счетчик непрочитанных сообщений
- Получить сообщение пользователя из кеша для распространения.
- Пользователь 2 входит в наш проект и переходит из автономного пользователя в онлайн-пользователя.
- Когда пользователь 2 входит в систему, запускается модуль запросов для получения текущих непрочитанных сообщений в каждой комнате.
- Модуль запросов запрашивает непрочитанные сообщения в Redis. Если в Redis нет данных, он продолжит запрашивать базу данных. Если нет, он вернет пользователю 0.
- Кэш Redis будет синхронизироваться с базой данных каждую минуту, чтобы обеспечить постоянство данных.
окружающая обстановка
-
Node: 8.5.0 +
-
Npm: 5.3.0 +
-
MongoDB
-
Redis
почему редис?
представлять
Redis является наиболее широко используемым промежуточным программным обеспечением для хранения данных в области интернет-технологий.Это аббревиатура от «Remote Dictionary Service» и представляет собой высокопроизводительную базу данных «ключ-значение». Он имеет преимущества чрезвычайно высокой производительности, богатых типов данных, атомов, богатых функций и т. д.
Redis имеет следующие 5 структур данных
- Строка - строка
- Хэш - словарь
- Список - список
- Сет - коллекция
- Sorted Set - упорядоченная коллекция
Чтобы узнать больше об этих 5 структурах хранения, вы можете просмотретьWOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO OFF.COM/MY 3C Note / Hot ...
Установить
windows
mac
brew install redis
ubuntu
apt-get install redis
redhat
yum install redis
centos
запустить клиент
redis-cli
Установка визуального инструмента
windows
mac
компиляция исходного кода
Структуры данных в проекте
В этом проекте мы используем String для хранения записей непрочитанных сообщений пользователя и используем его команду incr для выполнения операций автоинкремента. Используйте структуру Hash для хранения идентификатора сокета пользователя, когда наш веб-сокет подключен.
Как упоминалось выше, для подсчета используется структура данных Redis Stirng, В Redis наш счетчик ключей-значений выглядит так.
username-roomid - number
Пример: hua1995116-room1 - 1
Наш Socket-id представляет собой структуру Hash.
- socketId
- username - socketid
пример:
- socketId
- hua1995116 - En4ilYqDpk-P5_tzAAAG
MongoDB
Этот проект использует MongoDB с самого начала. Здесь не будут объясняться преимущества MongoDB, которые естественным образом сочетаются с Node. Модуль, который Node работает с MongoDB, называется mongoose. Для конкретных методов параметров вы можете проверить официальную документацию.
мангуст находится .com/docs/4.small/in…
Адрес загрузки MongoDB
Woohoo. MongoDB.com/download-testing…
Визуальный адрес загрузки
GitHub.com/Beauty VA UT in/Ade…
веб-сокет + реализация узла
Далее мы специально проиллюстрируем реализованный код в первых трех пользовательских сценариях.
Оффлайн-пользователи становятся онлайн-пользователями
Клиент отправит событие входа в систему при входе в систему, и ниже приведена логика бэкэнда.
// 建立连接
socket.on('login',async (user) => {
console.log('socket login!');
const {name} = user;
if (!name) {
return;
}
socket.name = name;
const roomInfo = {};
// 初始化socketId
await updatehCache('socketId', name, socket.id);
for(let i = 0; i < roomList.length; i++) {
const roomid = roomList[i];
const key = `${name}-${roomid}`;
// 循环所有房间
const res = await findOne({username: key});
const count = await getCacheById(key);
if(res) {
// 数据库查数据, 若缓存中没有数据,更新缓存
if(+count === 0) {
updateCache(key, res.roomInfo);
}
roomInfo[roomid] = res.roomInfo;
} else {
roomInfo[roomid] = +count;
}
}
// 通知自己有多少条未读消息
socket.emit('count', roomInfo);
});
Когда пользователь переходит из автономного состояния в онлайн-состояние, когда устанавливается подключение к сокету, будет отправлено событие входа в систему, и сервер будет запрашивать статус непрочитанного сообщения текущего пользователя, запрос из MongoDB и Redis соответственно, если в Redis нет данных. , это похоже на запрос к базе данных.
Онлайн-пользователь входит в комнату
Клиент отправит событие комнаты, когда он присоединится к комнате, ниже приведена внутренняя логика.
// 加入房间
socket.on('room', async (user) => {
console.log('socket add room!');
const {name, roomid} = user;
if (!name || !roomid) {
return;
}
socket.name = name;
socket.roomid = roomid;
if (!users[roomid]) {
users[roomid] = {};
}
// 初始化user
users[roomid][name] = Object.assign({}, {
socketid: socket.id
}, user);
// 初始化user
const key = `${name}-${roomid}`;
await updatehCache('socketId', name, socket.id);
// 进入房间默认置空,表示全部已读
await resetCacheById(key);
// 进行会话
socket.join(roomid);
const onlineUsers = {};
for(let item in users[roomid]) {
onlineUsers[item] = {};
onlineUsers[item].src = users[roomid][item].src;
}
io.to(roomid).emit('room', onlineUsers);
global.logger.info(`${name} 加入了 ${roomid}`);
});
Сервер получает событие комнаты, отправленное клиентом, для сброса непрочитанных сообщений в комнате пользователя, и пользователь присоединяется к списку комнат.
Отправить сообщение пользователю в комнате
Когда клиент присоединяется к комнате, он отправляет сообщение. Ниже приведена внутренняя логика.
socket.on('message', async (msgObj) => {
console.log('socket message!');
//向所有客户端广播发布的消息
const {username, src, msg, img, roomid, time} = msgObj;
if(!msg && !img) {
return;
}
... // 此处为向数据库存入消息
const usersList = await gethAllCache('socketId');// 所有用户列表
usersList.map(async item => {
if(!users[roomid][item]) { // 判断是否在房间内
const key = `${item}-${roomid}`
await inrcCache(key);
const socketid = await gethCacheById('socketId', item);
const count = await getCacheById(key);
const roomInfo = {};
roomInfo[roomid] = count;
socket.to(socketid).emit('count', roomInfo);
}
})
Этот шаг немного сложен, в основном из-за того, что пользователи в комнате отправляют сообщения, и нужно решить, какая часть пользователя должна учитываться, а какая часть пользователя не должна учитываться. считать, что пользователей, которых нет в комнате, нужно считать.
Дальше нам нужно пушить, так каких пользователей нужно пушить в реальном времени, правильно, тех юзеров, которые в сети, а не в комнате. Поэтому здесь также требуется судебное решение.
Это идеально и может точно подсчитывать пользователей и подталкивать их именно к тем пользователям, которые в них нуждаются.
постскриптум
Онлайн-демонстрация:www.qiufengh.com/
адрес гитхаба:GitHub.com/flower1995116/…
Если у вас есть какие-либо предложения или вопросы, вы можете присоединиться к группе WeChat для обсуждения.