使用socket解决,网页应用监控用户唯一在线

在这里我提供一种思路,因为考研原因,没有整理很详细的代码,希望大家谅解。

大家 真想解决这个问题的话,真的可以看一下,我的经验所获,绝对可以用。
不过小白可能看不懂,最好知道什么是Websocket,再懂一点点js代码就可以。

我们通常想的是,在数据库中增加两个字段,一是当前是否在线,二是在线过期时间,不过,如果只依靠数据库,是很难解决当用户直接关闭浏览器这一行为。我们无法准确监控这一行为。这也是网页应用中监控用户在线状态的一个最大的难点。

不过我们可以想到用ajax轮询的方式,如果超过xx秒没有发送轮询请求,就判定用户已经关闭浏览器,这样也是可以的,不过可能会有比较大的误差。

在这里我分享一个我发现的方法,亲测可用,如果是有实时聊天,弹幕等功能的项目,更是好用。就是使用WebSocket。

不但可以实时监控用户在线状态,防止同账户多地登录,还能使用socket的聊天等功能。

我下面的代码后端是node + express,前端是React的SPA,不过思路都是一致的。

首先,我们先建立socketIO连接。
前端代码不详细写了:注意这个:ws://localhost:4000/?userId=xxx连接ws时,把用户在前端的唯一标识(如主键,id号等)传到后端的socket,下面我都叫它主键。
最重要的一点,把socketSet要设置成全局变量,至少在登录和注册等模块可以使用。

后端:

结合我的解释看代码,socketSet是一个对象,里面属性名是用户主键,取出作为参数的主键:socket.handshake.query.userId,属性值是连接产生的socket对象。
而socketSet_ids也是一个对象集合,属性名是 socket.id ,属性值是userId(刚才传过来的主键)。

let socketSet = {
     }  //结构:{userId: socket, ......}
// 方便用户直接关闭浏览器,即突然断开socket连接时,有效删除Set中的socket
let socketSet_ids={
     }  //结构:{socket.id: userId, ......}  

exports.socketIO = function (server) {
     
    //得到IO对象
    const io = require("socket.io")(server)
    //监听连接(当有一个客户连接上时,后面的函数就会回调)
    io.on("connection", function(socket){
     
        //保存客户端的socket
        const _id = socket.handshake.query.userId
        socketSet[_id] = socket
        socketSet_ids[socket.id] = _id
        
        
        //接收客户端发送的消息,from是谁发,to是发给谁,content是内容
        socket.on("sendMsg", function({
     from, to, content}){
     
            .....
            .....
                if(socketSet[to]) {
     
                    console.log("对方在线消息发送:::")
                    socketSet[to].emit("receiveMsg", chatMsg)
                }
                socketSet[from].emit("receiveMsg", chatMsg)
            })
        })

    # 断开连接时的操作
        socket.on("disconnect", function(){
     
        ## 这样 的数据结构能快速删除指定socket,不用再遍历。
           delete socketSet[socketSet_ids[socket.id]]
        })
    })
}

//暴露出去,在用户退出登录时,移除指定元素
exports.socketSet=socketSet

这样我们就可以在用户登录或者是自动登录时,先获取到socketSet,再通过传递主键,来判断socketSet中是否有对应的属性值,如果有值,说明用户在线,如果没有值,说明用户没有在线,可以覆盖登录。

socketSet这样的数据结构有什么好处?
第一,就算不是SPA应用,也可以使用,在用户访问的每个页面建立WebSocket的连接,而不会socketSet中不会出现两个相同的socket对象。如果后台应用是java,则可以使用List类型来替代我的socketSet集合。
第二,通过socketSet的属性名是所谓的主键,前端用户的唯一标识,能快速对该对象集合进行操作(如删除)。
第三,用户退出登录操作时,也可以调用socketSet,删除其中对应主键的值。

socketSet_ids这样的数据结构有什么好处?
它没必要是全局变量,只要可以在关闭连接这个事件监听中可以使用即可。关闭socket时,我们什么都得不到,只能使用连接产生的socket对象,所以可以通过这个socket对象的唯一标识,快速查到对应的userId(主键),然后能删除socketSet中的对应值。

有什么看不懂的,或者有更好的思路的前辈,还可以联系我,qq: 1919213538

你可能感兴趣的:(node.js,java,python,javascript,reactjs)