websockt实现实时聊天讨论组

背景:

最近有个小项目,包括一个小功能就是讨论组聊天;
应用场景不是很大,给大家提供一种实现聊天室的思路;

存储用户信息

1.首先每个用户连接socket是由一个"key",我们需要存储这个key ,当分发消息的时候是需要用到这个;
2.讨论组不唯一,用户连接ws的时候需要连接所有的聊天室消息;
3.用map分连接的用户,当用户发送ws请求时,map添加用户的key;

router.ws('/:id', (socket, req) => {
    
    
 let channelArr = req.params.id.split(',')
     channelArr.forEach(item => {
    
    
        connectedMap.has(item) ? connectedMap.get(item).add(socket) : connectedMap.set(item, new Set().add(socket))
        console.log(`进入频道${
      
      item},当前在线人数${
      
      connectedMap.get(item).size}`)
    })
 })

分发消息

分发消息到我们map里所有的连接用户

    socket.on('message', function (msg) {
    
    
        let data = JSON.parse(msg)
        //存数据库
        //分发消息
        if (data.type === 'message') {
    
    
            broadcast(connectedMap.get(data.channel), JSON.stringify(data))
            //消息存储数据库
            saveMessage(data)
        }
    })

离开聊天室断开连接

 socket.on('close', function () {
    
    

        channelArr.forEach(item => {
    
    
            connectedMap.get(item).delete(socket)
            console.log(`离开频道${
      
      item},当前在线人数${
      
      connectedMap.get(item).size}`)
        })
    })

分发消息函数

function broadcast (conns, msg) {
    
    
    // 群发消息给所有用户
    conns.forEach(item => {
    
    
        item.send(msg)
    })
}

如果大型的app,并发数高;这种方法不适用;可采用Redis Channel 订阅redis消息,ws分发到各个用户这种办法

所有源码预览

const express = require('express')
const expressWS = require('express-ws')
const res = require('express/lib/response')
const router = express.Router()
const mysql = require('mysql')
expressWS(router)
let connectedMap = new Map()
let count = 0
const executeSql = require('../db/mysql')
const dateService = require('../untils/date')

//存放所有连接的用户
router.ws('/:id', (socket, req) => {
    
    
    let channelArr = req.params.id.split(',')
    console.log(channelArr)
    channelArr.forEach(item => {
    
    
        connectedMap.has(item) ? connectedMap.get(item).add(socket) : connectedMap.set(item, new Set().add(socket))
        console.log(`进入频道${
      
      item},当前在线人数${
      
      connectedMap.get(item).size}`)
    })
    /**
     * 传送格式
     * {
     *  type:'message',
     *  message:'',
     *  name:'',
     *  avatar:'',
     *  channel:'',
     *  userId:'',
     * }
     */
    socket.on('message', function (msg) {
    
    
        let data = JSON.parse(msg)
        //存数据库
        //分发消息
        if (data.type === 'message') {
    
    
            broadcast(connectedMap.get(data.channel), JSON.stringify(data))
            saveMessage(data)
        }
    })
    socket.on('close', function () {
    
    

        channelArr.forEach(item => {
    
    
            connectedMap.get(item).delete(socket)
            console.log(`离开频道${
      
      item},当前在线人数${
      
      connectedMap.get(item).size}`)
        })
    })
})

function broadcast (conns, msg) {
    
    
    // 群发消息给所有用户
    conns.forEach(item => {
    
    
        item.send(msg)
    })
}
//单独发送给一个用户
function sendMsg (conn, type, data) {
    
    
    conn.send(JSON.stringify({
    
     type: type, data: data }))
}
router.get('/getGroups', async (req, res) => {
    
    
    const userId = req.query.userId
    const sql = 'SELECT id, group_name FROM group_info WHERE id IN (SELECT group_id FROM group_member WHERE user_id = ?)'
    try {
    
    
        const result = await executeSql(sql, [userId])
        res.json({
    
     code: 200, data: result })
    } catch (error) {
    
    
        console.error(error)
        res.status(500).json({
    
     message: 'Internal server error' })
    }
})
//聊天记录存数据库函数
async function saveMessage (data) {
    
    

}
module.exports = router

猜你喜欢

转载自blog.csdn.net/DragonOfMoon/article/details/130134699