当vue遇到socket.io制作在线离线状态

2,468 阅读4分钟

socket.io简介与使用

在Http协议中,客户端与服务器端的通信是靠客户端发起请求,然后服务器端收到请求再进行回应,这个过程中,客户端是主动的,服务器端是被动的。Websocket协议就不一样了,它是基于TCP的一种新的网络协议,它与Http协议不同之处就在于Websocket能实现服务器端主动推送消息到客户端,服务器端与客户端都能发起通信,这一次,服务器端终于也拥有了主动权。有了它,我们能更方便快捷地实现服务器端与客户端之间的实时通讯。

将 socket.io 绑定到服务器上,于是任何连接到该服务器的客户端都具备了实时通信功能。 io.sockets.on('connection', function (socket) { ... }) 的作用是服务器监听所有客户端,并返回该新连接对象,接下来我们就可以通过该连接对象(socket)与客户端进行通信了。你可以看到不管是服务器还是客户端都有 emit 和 on 这两个函数,可以说 socket.io 的核心就是这两个函数了,通过 emit 和 on 可以轻松地实现服务器与客户端之间的双向通信。

emit :用来发射一个事件或者说触发一个事件,第一个参数为事件名,第二个参数为要发送的数据,第三个参数为回调函数(一般省略,如需对方接受到信息后立即得到确认时,则需要用到回调函数)。

on :用来监听一个 emit 发射的事件,第一个参数为要监听的事件名,第二个参数为一个匿名函数用来接收对方发来的数据,该匿名函数的第一个参数为接收的数据,若有第二个参数,则为要返回的函数。

socket.io 提供了三种默认的事件(客户端和服务器都有):connect 、message 、disconnect 。当与对方建立连接后自动触发 connect 事件,当收到对方发来的数据后触发 message 事件(通常为 socket.send() 触发),当对方关闭连接后触发 disconnect 事件。

此外,socket.io 还支持自定义事件,毕竟以上三种事件应用范围有限,正是通过这些自定义的事件才实现了丰富多彩的通信。

最后,需要注意的是,在服务器端区分以下三种情况:

socket.emit() :向建立该连接的客户端广播

socket.broadcast.emit() :除自己外建立该连接的客户端的所有客户端广播

io.sockets.emit() :向所有客户端广播,等同于上面两个的和

在线离线功能

在线功能

当用户登录成功的时候要通过socket.io发送一个登陆成功事件,服务器收到了这个事件去数据库查找登录人,把登录人的状态变为在线状态,同时通知其他人,刷新其他人的人员状态,

离线功能

当用户退出(按手机的返回键)或者socket.io断开会触发一个socket.io里面的一个disconnect事件,我们通过这个事件来让当前退出的用户状态变为离线状态;当用户手动触发事件退出,可以通过socket.io发送一个退出事件,吧当前用户的ID值传给服务器,服务器拿到当前要退出用户的id值,查询数据库更改状态,然后通知其他人刷新页面;

重点难点 disconnect事件是不能传参的,服务器中又不知道当前离开的用户是谁,那么我们怎么知道当前离开的用户是谁呢?

解决 当用户登录成功的时候通过socket.io发送一个登陆成功的事件,服务器得到通知,通过socket.id可以得到当前socket连接的唯一ID值,我们吧这个ID值存在当前登录人的数据库中,当用户离开或者断开连接或者连接失效的时候,通过socket.io里面自己的一个disconnect事件,通过disconnect里面的socket中的id值去数据库查询我们之前登录成功存在数据库的那个ID值,然后更改他的状态,通知其他所有人、把人员状态更改。这样就可以做实时的在线离线功能;

// 发送登录成功消息
  send_loginSuccess({
                      commit,
                      state
                    }, val) {
    socket.emit("loginSuccess", val)
  },

  // 接受登录消息
  send_getloginSuccess({
                         commit,
                         state
                       }, val) {
    socket.on('getloginSuccess', (data) => {
      let list = data.filter(item => {
        return item._id !== state.userList._id
      })
      let item=data.find(item => {
        return item._id === state.userList._id
      })
      commit('set_personList', list)
      commit('set_users',item||{})
      commit('set_isLogin')
    })
  },
io.on('connection', socket => {
    socket.on('disconnect', async () => {
        try {
            await User.updateOne({ socketId: socket.id }, { $set: { online: false } }).exec();
            let userList = await User.find({}, {__v: 0 }).limit(50).sort({ online: -1 }).exec()
            socket.broadcast.emit('getloginSuccess', userList)
        } catch (e) {
            console.log(e)
        }
    });
    
    socket.on('loginSuccess', async data => {
        try {
            await User.updateOne({ _id: data }, { $set: { online: true, socketId: socket.id } }).exec();
            let userList = await User.find({}, { __v: 0 }).limit(50).sort({ online: -1 }).exec()
            socket.broadcast.emit('getloginSuccess', userList)
        } catch (e) {
            console.log(e)
        }
    })
    socket.on('loginOut', async data => {
        try {
            await User.updateOne({ _id: data }, { $set: { online: false } }).exec();
            let userList = await User.find({}, { passwd: 0, __v: 0 }).limit(50).sort({ online: -1 }).exec()
            socket.broadcast.emit('getloginSuccess', userList)
        } catch (e) {
            console.log(e)
        }
    })
})

移动端(微信)访问

二维码

app下载

微信扫码之后请选择在浏览器打开,更好体验请选择下载app体验

app

后端的代码暂时不开放出来,因为涉及到很多个人的配置数据,如果实在需要可以加我qq 384434682

项目概况

登录
发送消息