项目介绍
基于websocket的一个简单的聊天室
技术栈 express+socket.io+animate.css+angular
关于websocket不了解的点我,而socket.io是对websocket进行封装,提供通用接口。
Github项目地址
安装与使用
1 2 3 4 5 6 7
| git clone https://github.com/ShanaMaid/websocket-express-webchat.git #下载项目 npm install #安装依赖 node app.js #启动服务 访问 http://localhost/ #进入聊天室
|
功能
- 进入房间通知
- 离开房间通知
- 消息接收与发送
- 在线列表
- 服务器端信息备份
动态GIF
实现
思路
利用on绑定事件,emit触发绑定事件,服务器端与客户端进行交互
1 2
| socket.on(eventName,callBack) #绑定事件,eventName可以自定义 socket.emit(eventName,data) #触发事件,发送data
|
更多关于socket.io的详细信息请移步官方文档,点我。
服务端
首先添加我们需要使用的模块
1 2 3
| var express = require('express'); var socket = require('socket.io'); var fs = require('fs');
|
然后从配置文件config.json读取一些我们需要的关于聊天室的一些配置信息,关于配置文件
1 2 3 4
| var history_num = config.history_num ; //服务器缓存的历史消息条数 var port = config.sever_port; //端口号 var backup = config.backup; //是否开启备份 var backup_filename = config.backup_filename; //备份文件名字
|
定义person与history两个数组,用于存储在线人员的名称与服务端缓存的消息条数(即用户第一次进入聊天室推送的历史消息条数)
1 2
| var person = [];//记录在线情况 var history = [];//需要缓存的消息
|
监听port端口号,创建一个socket对象io
1 2 3
| var app = express(); var server = app.listen(port); var io = new socket(server);
|
编写connection事件,响应客户端的连接请求,返回客户端socket,编写客户端要emit的事件
…………………………
表示代码省略部分,完整代码点击Github项目地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| io.on('connection', (socket) => { ………………………… socket.emit('history',history); #发送服务器记录的历史消息 io.sockets.emit('updatePerson', person); #进行广播,触发所有客户端的updatePerson事件,更新在线列表人员 ………………………… socket.on('sendMsg', (data) => { #发送消息事件 ………………………… io.sockets.emit('news',obj); #进行广播,触发所有客户端的news事件,更新信息。 }); socket.on('setUserName',(data) => { #设定用户名事件 ………………………… io.sockets.emit('updatePerson',person); #进行广播,触发所有客户端的updatePerson事件,更新在线列表人员 io.sockets.emit('news',{content:user+'进入房间',time:Now(),name:'系统消息'}); #进行广播,触发所有客户端的news事件,通知进入房间 ………………………… }); socket.on('disconnect', (socket) => { #掉线事件 if(user!='') { person.forEach((value,index)=>{ if (value===user) { person.splice(index,1); } }); io.sockets.emit('news', {content: user + '离开房间', time: Now(), name: '系统消息'}); io.sockets.emit('updatePerson', person); } }); });
|
客户端
变量初始化
1 2 3 4 5 6
| $scope.data = []; #接收-消息队列 $scope.name = ''; #用户名 $scope.content = ''; #发送信息内容 $scope.personnum = 0; #在线人数 $scope.personlist = []; #在线人员列表 $scope.flag = false; #是否取名
|
创建客户端socket
1 2
| const socket_url = 'http://localhost'; var socket = io(socket_url);
|
完成服务器端的emit的事件
1 2 3 4 5 6 7 8 9 10 11
| socket.on('news', (data) => { …………………… }); socket.on('history', (data) => { …………………… }); socket.on('updatePerson', (data) => { …………………… });
|
config.json配置文件
1 2 3 4 5 6
| { "history_num":20, #服务器缓存的历史信息条数 "sever_port":80, #服务器监听端口号 "backup":true, #是否开启服务端信息备份 "backup_filename":"./backup/example.json" #备份文件名字 }
|
聊天信息备份
聊天信息以json格式存储在example.json文件中!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function backupMsg(filename,obj) { var backup_file = fs.readFileSync(backup_filename); var msg= backup_file!='' ? JSON.parse(backup_file) : []; msg.push(obj); var str = '[\n' msg.forEach((value,index) =>{ if (index!==0){ str+=',\n'; } str += ' {\n "name":"'+value.name+'",\n "time":"'+value.time+'",\n "content":"'+value.content+'"\n }' } ); str += '\n]'; fs.writeFile(filename, str, (err) => { if(err) console.log("fail write :" + arr + " "+Date() + "\n error:"+err); }); }
|
备份信息示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| [ { "name":"测试人员1", "time":"2017-2-13 23:32:17", "content":"一条简单的测试信息" }, { "name":"测试人2", "time":"2017-2-13 23:33:42", "content":"那你很棒哦" }, { "name":"测试人3", "time":"2017-2-13 23:33:54", "content":"肯定很棒哦" } ]
|
总结
websocket实现了浏览器与服务器全双工通信。
举个栗子,原来是这样的
轮询机制:
1 2 3 4 5 6 7 8 9
| 客户端:服务器,你有没有消息要给我啊? 服务器:有。 客户端:服务器,你有没有消息要给我啊? 服务器:没有。 ——————————无限重复———————————— 客户端:服务器,你有没有消息要给我啊? 服务器:没有。 客户端:服务器,你有没有消息要给我啊? 服务器:你烦不烦啊~
|
而现在的websocket:
1 2 3 4 5
| 客户端:服务器,你有我的消息了记得call我。 服务器:OK! ——————————当有消息的时候———————— 服务器:有你的消息了,客户端。 客户端:收到。
|
##后记
- 聊天室在线人员显示错误,多人离线时会出现在线列表混乱。目前已修复
- 聊天室历史加载记录,存在错误,已修复!
Github项目地址,欢迎各位交流学习!