Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

使用socket.io遇到的一些坑 #6

Open
lensh opened this issue Jul 26, 2017 · 1 comment
Open

使用socket.io遇到的一些坑 #6

lensh opened this issue Jul 26, 2017 · 1 comment

Comments

@lensh
Copy link
Owner

lensh commented Jul 26, 2017

一、給指定的用户发送消息

为了给指定的用户发送消息,我们需要建立一张hash表,键为用户的id,值为该用户连接时生成的socketid。并把这张表以json的格式存储在服务端的users.json文件里。每次登陆的时候就把用户的id和socketid存储到服务器端。具体怎么实现可以参考问题二里的服务端代码。

二、用户手动刷新或者重新打开浏览器,原来的socketid会失效

如果用户手动刷新或者重新打开浏览器(都可视为刷新),那么服务器端保存的该用户对应的socketid会失效,因为刷新会导致connection,会生成新的socketid。这样导致的问题就是服务端无法继续给指定的用户推送消息了(socketid失效)。

解决方案如下:
客户端:每次连接服务端的时候就emit用户的id。当然得先判断下用户是否已经登陆了,没有登陆的话,自然无法获取用户的id,无法emit,这种情况就只能等用户登陆了再emit用户的id。

客户端需要在两个地方emit用户的id:
(1)登录时(emit用户id)

  //登陆后的回调
 callback({code,data,message}){ 
      if(code==1){
        socket.emit('login',data.loginStatus.userId)  // emit login事件,传递用户id
        this.$store.commit('SET_LOGIN',data)  //设置store状态
        this.$router.push('message')
      }else{
        this.$store.dispatch('setShowWarn',message)
      }
  }

(2)连接时(需判断是否已经登陆)

    <script src="http://localhost:3000/socket.io/socket.io.js"></script>
    <script>
      const socket = io.connect('http://localhost:3000/')

      //解决用户手动刷新浏览器后,原来的socketid失效的问题
      const loginStatus= JSON.parse(localStorage.getItem("loginStatus") || '{}')
     // emit update事件,传递用户id
      loginStatus.isLogin && socket.emit('update',loginStatus.userId)   
    </script>

服务端:同时监听login事件和update事件

import socketHander from './socket'    //socket要实现的具体逻辑
//这里省略其它导入

// socket事件
io.on('connection', (socket) => {
	const socketId=socket.id
	//监听用户登录
	socket.on('login', (userId) => {
		//保存用户的id和socketid
		socketHander.saveUserSocketId(userId, socketId)
	})
	//监听用户刷新
	socket.on('update', (userId) => {
		//保存用户的id和socketid
		socketHander.saveUserSocketId(userId, socketId)
	})
})

socket.js:

import {
	readFile,
	writeFile
} from './fs-async'

const filePath = `${__dirname}/users.json`

// socket具体业务逻辑
export default class socketHander {
	/**
	 * [saveUserSocketId 保存用户的id和socketid]
	 * @param  {[type]} userId   [用户id]
	 * @param  {[type]} socketId [用户的socketid]
	 * @return {[type]}          [description]
	 */
	static async saveUserSocketId(userId, socketId) {
		let data = await readFile(filePath).catch((err) => {
			console.log(err)
		})
		data[userId] = socketId
		writeFile(filePath, data)
	}
}

fs-async.js:

import fs from 'fs'

/**
 * [读取文件的内容]
 * @param  {[type]} filePath [文件路径]
 * @return {[type]}          [description]
 */
export const readFile = (filePath) => {
	return new Promise((reslove, reject) => {
		fs.readFile(filePath, 'utf8', (err, data) => {
			if (!err) {
				reslove(JSON.parse(data))
			} else {
				reject(err)
			}
		})
	})
}

/**
 * [写文件]
 * @param  {[type]} filePath [文件路径]
 * @param  {[type]} data     [新的文件数据]
 * @return {[type]}          [description]
 */
export const writeFile = (filePath, data) => {
	return new Promise((reslove, reject) => {
		fs.writeFile(filePath, JSON.stringify(data), (err) => {
			if (err) {
				reject(err)
			}
		})
	})
}

users.json:

{}

三、socket事件重复监听的问题
在单页应用里,使用socket.on监听事件前一定要先移除原来的事件。不然会导致生成重复的监听器。

 //通过socket来更新消息
 updateBySocket(){
      socket.removeAllListeners()  //一定要先移除原来的事件,否则会有重复的监听器

      socket.on('receivePrivateMessage',(data)=>{
          this.$store.commit('UPDATE_MESSAGE',{
            from_user:data.from_user_beizhu,
            id:data.from_user,
            imgUrl:data.from_user_face,
            message:data.message,
            time:data.time,
            type:'single'
          })
      })
      socket.on('receiveGroupMessage',(data)=>{
          //如果不包含自己,则直接丢弃这个socket消息
          if(!data.group_member.includes(this.userId-0))  return

          this.$store.commit('UPDATE_MESSAGE',{
            from_user:data.group_name,
            id:data.group_id,
            imgUrl:data.group_avator,
            message:`${data.from_user_nick_name}:${data.message}`,
            time:data.time,
            type:'group'
          })
      })
 }
@MechaGirls
Copy link

刚好碰到这个socket事件重复监听的问题,谢谢。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants