200行代码实现web在线聊天室

  |  
 阅读次数

项目介绍

基于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项目地址,欢迎各位交流学习!