基于Vue+node+Socket.io的在线多人聊天室

ASDF-JKL 2022-01-15 03:08:19

一、设计方案

1.设计背景

    随着互联网的发展,远程办公学习需要的日渐增多。因此本方案旨在设计一种简易的在线多人聊天室系统,实现多用户的相互交流。

2.设计框架

    本项目主要使用Vue+Express(node.js)框架,使用Socket.io实现前后端的通信。

(1)前端框架Vue概述:

    Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

(2)后端框架Express概述:

    Express 是一个属于 Node 平台的 Web 应用开发框架,它提供了一系列的强大特性,帮助你创建各种 Web 应用,使用所选择的各种 HTTP 实用工具和中间件,快速方便地创建强大的 API。Express 提供精简的基本 Web 应用程序功能,而不会隐藏您了解和青睐的 Node.js 功能。许多流行的开发框架都基于 Express 构建。

(3)Socket.io概述:

    node.js提供了高效的服务端运行环境,但是由于浏览器端对HTML5的支持不一,为了兼容所有浏览器,提供卓越的实时的用户体验,并且为程序员提供客户端与服务端一致的编程体验,于是socket.io诞生。Socket.io将Websocket和轮询 (Polling)机制以及其它的实时通信方式封装成了通用的接口,并且在服务端实现了这些实时机制的相应代码。

3.功能设计

(1)用户的登入与登出功能

     用户可以通过用户名(昵称)作为用户标识进入聊天室,用户进入与离开聊天室都会群发系统消息提示所有用户。当用户欲使用的用户名与聊天室内其他用户用户名重复时,将弹出错误提示。

(2)聊天室的当前人数统计功能

     系统将实时统计更新聊天室内的用户人数,并显示在顶部。

(3)用户的消息发送与接收功能

    用户可以发送消息,该消息将自动转发给聊天室内其他用户。

(4)利用Session实现的用户识别功能

    若用户退出聊天室并在一定时间内重新进入聊天室,即断连后重连,利用Session中的信息我们可以识别出这个用户为旧用户。

二、项目演示

1.用户登入

首先,我们在输入栏中输入“ZZY569”作为第一个登录用户的用户名。

 

之后,我们在另一个终端尝试用同一个用户名登入聊天室,这时系统检测到该用户名与当前用户列表中某一用户名重复,于是弹出错误提示,要求用户更换用户名。

 

2.聊天室用户统计

 

在我们登录了第一个用户后,我们在其他两个终端分别用“ZZY”和“569”作为用户名登入该聊天室。如上图所示,这是我们在第一个登录用户的界面看到的信息,可见三人依次登入聊天室,并且聊天室当前总人数为3人。

 

3.用户消息发送与接收

用户1首先发送消息“hello”:

其他用户接收到该消息,其中显示了发送用户的ID与发送时间:

 

4.用户登出与利用Session实现的用户重连识别

 用户3离开聊天室,我们从用户1的界面看到用户3的断连提示,以及聊天室总人数的变化。

 

 用户3重新进入该聊天室,系统查询到Session中存有该用户的数据,因此便显示重连提示(reconnected),而不像首次进入那样显示“569 has joined the Chatroom”。

 

 

三、源代码分析

1.用户登入登出部分

(1)用户登入

在前端,用户输入用户名并点击login按钮后,通过向服务端发送登录事件,若用户名为空,则提示用户输入用户名:

    /*登录*/
    login:function(){
      var vm = this;

      if(vm.uname){
        vm.socket.emit('login',{username:vm.uname})
      }else{
        alert('Enter Username')
      }
    },

在服务端,监听socket中的登录事件,当接收到相应数据后,比较当前用户名是否与用户列表中所有用户名重复,若不重复则识别为一个新用户,isNewPerson=ture,认为登陆成功,否则置为false:

	/*监听登录*/
	socket.on('login',function(data){
		for(var i=0;i<users.length;i++){
	        if(users[i].username === data.username){
	          	isNewPerson = false;
	          	break;
	        }else{
	          	isNewPerson = true;
	        }
	    }

若登陆成功,则向前端发送登录成功信息,并向所有客户广播该用户登录事件,以及聊天室人数变更的事件:

	        	/*登录成功*/
	        	socket.emit('loginSuccess',{username:data.username});

		        /*向所有连接的客户端广播事件*/
		         io.sockets.emit('receiveMessage',resdata);

	        	console.log('登录成功:',resdata)
		        console.log('当前连接的用户为:',users);

		        io.sockets.emit('amountChange',users.length);

若登陆失败,则向前端发送登录失败事件:

	        socket.emit('loginFail','');

前端监听并收到服务端的返回事件后,进行相应的处理并更新数据:

    /*登录成功*/
    vm.socket.on('loginSuccess',function(data){
        vm.name = data.username;
        vm.isCheckin = true;
    })

    /*登录失败*/
    vm.socket.on('loginFail',function(){
      alert('Please Use A New Name')
    })

    /*监听人数变化事件*/
    vm.socket.on('amountChange',function(data){
      vm.amount = data
    })

(2)用户登出

用户退出界面后,服务端检测到socket断开,便向所有用户广播用户离开事件以及人数变更事件:

	/*退出登录*/
	socket.on('disconnect',function(){
		
		let resdata = {
        	msgType: 0,
        	msgDate:  new Date(),
        	message: 'SysInfo:'+username+' has disconnected',

        };
        io.sockets.emit('receiveMessage',resdata);

		/*向所有连接的客户端广播事件*/
      	io.sockets.emit('leave',username);
      	users.map(function(val,index){
        if(val.username === username){
          	users.splice(index,1);
        }
        /*发送人数变更事件信息*/
        io.sockets.emit('amountChange',users.length);


      })
    }

2.用户人数统计部分

每当用户人数变更后,服务端便会广播人数变更事件,并携带当前人数信息:

		io.sockets.emit('amountChange',users.length);

客户端监听到人数变化后,便更新相应数据,从而用户可以在页面上看到人数的实时变化:

    /*监听人数变化事件*/
    vm.socket.on('amountChange',function(data){
      vm.amount = data
    })
	<h1>Chatroom(TotalNumber:{{amount}})</h1>

3.消息发送与接收部分

(1)消息发送

用户在前端点击“发送”按钮就会触发发送消息事件,通过socket将改时间以及用户输入的消息发送给服务端。若用户输入的消息为空,则会提示用户输入具体信息:

    /*发送消息*/
    sendMessage:function(){
      var vm = this;

      if(vm.inputMsg){
        vm.socket.emit('sendMessage',{username:vm.uname,message:vm.inputMsg});
        vm.inputMsg = '';
      }else{
        alert('Please Enter……')
      }
    },

服务端监听到用户发送消息后,便会在用户的输入文字的基础上加入一些附加信息,比如发送用户名,信息类型与时间信息等,之后便产生一个接受信息的事件,把该信息广播给所有用户:

	/*监听到客户发送消息*/
	socket.on('sendMessage',function(data){
		let resdata = {
			username: data.username,		/*发送方用户名*/
			msgType: 1, 			/*信息类型:0为系统消息,1为用户消息*/
			msgDate:  new Date(), 	/*加入时间信息*/
			message: data.message,

		}
        io.sockets.emit('receiveMessage',resdata);
    })

前端收到服务端的接受信息事件后,将其中的信息呈现给用户:

    vm.socket.on('receiveMessage',function(data){
      vm.msgList.push(data);
      window.scrollTo(0, document.getElementById('chat_con').scrollHeight);
    })

并且根据信息的类型(0为系统消息,1为用户消息)呈现的格式有所不同。同时,若信息为用户消息,且根据发送用户名的情况,呈现的格式也有所不同。若发送用户名与当前用户名相同,则信息呈现在右侧,表示为自己发送的消息,反之,则呈现在左侧,代表他人发送的消息。

              <template v-if="item.msgType==0">
                 <p >{{item.message}}</p><br/>
              </template>

              <template v-else>
                  <div class="chat-item item-right clearfix" v-if="uname == item.username "><span class="img fr"></span><span class="message fr">{{item.message}}</span></div>
                  <div class="chat-item item-left clearfix rela" v-else><span class="abs uname">{{item.username}}  ( {{item.msgDate | formatDate}} )</span><span class="img fl"></span><span class="fl message">{{item.message}}</span></div>
              </template>

 

4.利用Session数据识别旧用户

在用户断连后,相应的session仍会保留其信息一段时间。在用户重连时,我们判断其对应的session中用户数据是否存在,若存在,则判断该用户是一个重连用户,在对应的登录广播信息中我们设置为'has reconnected',表示其是重连的用户:

			if (socket.handshake.session.userdata){       

				username = data.username;
				users.push({
		 		username:data.username
				})

				let resdata = {
					msgType: 0, 	
					msgDate:  new Date(), 	
					message: 'SysInfo:'+data.username+' has reconnected',
				}

				/*登录成功*/
				socket.emit('loginSuccess',{username:username});

				  /*向所有连接的客户端广播事件*/
				 io.sockets.emit('receiveMessage',resdata);

				io.sockets.emit('amountChange',users.length);
		
  			}

该功能可根据需求进行优化,比如在使用用户名+密码的登录方式中,检测到为重连用户,可以让其不输入密码而直接登录。

 

作者:NP569

...全文
151 回复 打赏 收藏 举报
写回复
回复
切换为时间正序
请发表友善的回复…
发表回复
发帖
代码中的软件工程

391

社区成员

软件工程教学新范式,强化专项技能训练+基于项目的学习PBL。Git仓库:https://gitee.com/mengning997/se
社区管理员
  • 码农孟宁
加入社区
帖子事件
编辑了帖子
2022-01-15 03:10
创建了帖子
2022-01-15 03:08