利用socket.io实现用户实时聊天

聊天存入数据库需要的参数标识:
	两个用户的标识
	聊天消息内容
	发送消息的时间
	当前对话消息的标识


1、在前台的异步请求中,使用socket来发送消息
	向后台发送时,应该将两个用户的标识传递,且能看出谁向谁发,还要携带聊天内容
	
2、在后台中,使用socket来接收,不需要路由组件,写成外部模块来接收
		后台收取到后存入数据库中,并向客户端返回存入的内容
			其中:因为客户端都是监听的相同名称,所以都能收到服务器返回的发送内容
			
3、在用户登录等时候,就向后台发送请求,获取消息列表
	通过当前对话消息的标识,确定当前对话的消息
	通过用户的标识,确定谁发送
	通过消息的时间标识,确定谁先发送
	
4、实时同步每条消息
	消息发送后,后台接收存入数据库然后将发送的消息发挥前端,前端监听接收后,将触发方法使得消息列表增加该消息,如reducer中增加一个case,来使得消息列表增加

基于React的Redux模式下的代码示例:
actions.js中异步方法使用socketio发送:

 function initIO(dispatch,userid)
 {
      if(!io.socket){
          io.socket=io('ws://localhost:4000')
          io.socket.on('receiveMsg', function (chatMsg) {
               console.log('浏览器端接收到消息:', chatMsg)
               //只有当前会话才分发action保存
               if(userid==chatMsg.from||userid==chatMsg.to)
               {
                    dispatch(receiveMsg(chatMsg))
               }
          })
      }
 
 }

 //异步发送消息
 export const sendMsg=({from,to,content})=>{
      return dispatch=>{
          initIO();
          console.log('浏览器发送消息',{from,to,content})
          io.socket.emit('sendMsg',{from,to,content})
      }
 }

后台:

let express = require('express')
var bodyParser = require('body-parser');
var md5=require('blueimp-md5');
var cookieParser = require('cookie-parser');

var urlencodedParser = bodyParser.urlencoded({ extended: false });

const {UserModel,ChatModel} =require('./db/models');
const filter={password:0,__v:0};

var app=express();

//socket.io
var server = require('http').Server(app);
require('./socketio/test')(server);

server.listen(4000,function(){
    console.log('this express server is running at http://127.0.0.1:4000 ');
});

app.use(cookieParser());

...

引入的模块:

const {ChatModel}=require('../db/models')

module.exports = function (server) {
    // 得到 IO 对象
    const io = require('socket.io')(server)

    //监视连接(当有一个客户连接上时回调)
    io.on('connection', function (socket) {
        console.log('soketio connected')

        // 绑定 sendMsg 监听, 接收客户端发送的消息
        socket.on('sendMsg', function ({from,to,content}) {
        
            console.log('服务器接收客户端发送',{from,to,content})
            //保存消息进数据库,再将保存信息返回给前台
            const chat_id=[from,to].sort().join('-');
            const create_time=Date.now();
            //存入数据库
            new ChatModel({from,to,content,chat_id,create_time}).save(function(err,chatMsg){
                //向客户端发送数据
                io.emit('receiveMsg',chatMsg);
            })
        })
    })
}

获取消息列表:

//异步获取消息函数
 async function getMsgList(dispatch,userid)
 {
     initIO(dispatch,userid);
     const response =await reqChatMsgList();
     const res=response.data

     if(res.code===0)
     {
          const{users,chatMsgs}=res.data
          dispatch(receiveMsgList({users,chatMsgs}))

     }
 }

前台获取到消息后,根据标识对消息的处理:

       const {user}=this.props
       const {users,chatMsgs}=this.props.chat
       
       //计算当前聊天的chatId
       const meId=user._id;
       if(!users[meId])
       {
           return null;
       }
       const targetId=this.props.match.params.userid;
       const chatId=[meId,targetId].sort().join('-');
	   
	   //获取当前对话的所有消息
       const msgs=chatMsgs.filter(msg=>msg.chat_id==chatId)
       //头像
       const targetHeader=users[targetId].header;

       const targetIcon=require(`../../assets/imgs/${targetHeader}.png`)
	   
	   return
           {
            msgs.map(msg=>{
                 if(meId===msg.to) //对方发给我的
                 {

                     return  <Item
                             key={msg._id}
                              thumb={targetIcon}
                             >
                                 {msg.content}
                             </Item>
                 }else{
                     return  <Item
                              key={msg._id}
                              className='chat-me'
                              extra='我'
                             >
                                 {msg.content}
                             </Item>
                 }
             })
         }

reducer:

//聊天状态
const initChat={
    users:{},
    chatMsgs:[],
    unReadCount:0 //总未读数量
}
function chat(state=initChat,action)
{
    switch(action.type)
    {
        case RECEIVE_MSG_LIST:
            const {users,chatMsgs}=action.data
            return {
                users,
                chatMsgs,
                unReadCount:0
            }
        case RECEIVE_MSG:
            const chatMsg=action.data
            return {
                users:state.users,
                chatMsgs:[...state.chatMsgs,chatMsg],
                unReadCount:0
            }
        default:
            return state
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章