费话不多说,先上图DEMO地址:hemaj.com
**
node服务器代码
**
var WebSocketServer = require('ws').Server;//WebSocketServer模块
var uuid = require('node-uuid');//uuid生成模块
var fs=require("fs");//系统文件模块
var src=require('./app/models/upimg');//自定义保存图片模块调用
var Chatnumber={};//新建聊天室对象
//加载已经建立的聊天室文件
//fs.readFile:异步读取文件
fs.readFile('chat.txt', function (err, data) {
if (!err){//读取成功时,把取值转化成对像,
var be=JSON.parse(data.toString());
for(var i in be){//由于be内部包含对象也要做JSON.parse()解析,
be[i]=JSON.parse(be[i]);//解析对象中对对象
}
Chatnumber=be;
}
chatsever();//触发服务事件
});
function chatsever(){
//创建WebSocketServer 服务器,端口为8181;
wss = new WebSocketServer({ port: 8181});
var dataIndex =0;//统计在线人
//connection用于客户端建立tcp连接
wss.on('connection', function (ws) {//ws是当前连用户对象,通信全靠他
dataIndex += 1;
console.log('在线总用户:'+dataIndex);
//message是收到客户端消息,进行触发
ws.on('message', function (data){
data=JSON.parse(data); //data是客户端传过json数据对象
var id=data['id'];//聊天室ID
var uid=data['uid'];//用户id
var state=data['state'];//请求数据类型,0创建聊天房间,1新用户加入,2收到消息,3请求在线人员,4请求聊天室房间列表信息,
var user=data['user'];//用户信息
var message=data['text'];//发送内容
if(!uid){//uid不存时候,创建一个uid
var client_uuid = uuid.v4();
}else{
client_uuid=uid
}
//把用户uid和id储存,在用户关闭时候用
ws.uid=client_uuid;
ws.id=id;
switch(state){
case 0://0创建聊天房间
var pic=data['pic'];//房间图片
var title=data['title'];//标题
var miaoshu=data['miaoshu'];//描述
var renshu=data['renshu'];//人数
var pw=data['pw'];//设置密码
//src.upimg()封装存图片函数,pic是图片地址或base64
//imgpath存在服务器的路径设置,function(data){}是回调涵数
//data图片储存成功后生成路径
var imgpath='./Uploads/chatpic/';
src.upimg(pic,imgpath,function(data){
var clients=[];//用天储存用户数组
//把创建用户信息存在里去
clients.push({'uid':client_uuid, "ws": ws,'user':user});
//组建新聊天室数据对象
var obj={'id':id,'clients':clients,'pic':data,'title':title,'miaoshu':miaoshu,'renshu':renshu,'pw':pw};
//并且储存Chatnumber对象
Chatnumber[id]=obj;
var u={'state':0,'uid':client_uuid,'id':id}//返回给客户端数据
console.log('创建房间成功'+id);
console.log(Chatnumber);
ws.send(JSON.stringify(u)); //ws.send()发送给当前用户
});
break;
case 1://1新用户加入
if(Chatnumber[id]){
//判断当前房间存在
var clients=Chatnumber[id]['clients'];
var b=false;
var index;
for(var i in clients){
//检查用户uid是否存在房间里
if(clients[i]['uid']==client_uuid){
b=true;
index=i;
break;
}
}
if(!b){//有房间时,检查一下该用户存不在
//把新用户追加到clients用户组进来
clients.push({'uid':client_uuid, "ws": ws,'user':user});
}else{//用户存在,重新ws对易县存值
clients[index]['ws']=ws;
console.log('存在');
}
//返回数据
var u={'state':1,'uid':client_uuid,'title':Chatnumber[id]['title'],'miaoshu':Chatnumber[id]['miaoshu']}
ws.send(JSON.stringify(u));//ws.send()发送给当前用户
return false;
}else{//当房间不存时候,返回数组
var u={'state':404,'msg':'当前房间不存在'};
ws.send(JSON.stringify(u));//ws.send()发送给当前用户
return false;
}
break;
case 2://2收到消息
if(message){
//message收到消息对象
var obj=Chatnumber[id];//获取房间对象
var pic=message['pic'];//获取用户发送消息只图片
var newpath=[];
//发消息只图片存在时,保存服务器,如果你服务器好话,你也可以不存了,直接转发
if(pic.length>0){//聊天图片生成
var imgpath='./Uploads/chatimg/';//聊天发送图片
for(var i in pic){//多张图做个循环生成
//生成图片是个异步事件
src.upimg(pic[i]['src'],imgpath,function(data){
message['pic'][i]['src']=data;//把发送消息对象图片数据转用路径
newpath.push(data);
});
}
}
//由于是生成图片是个异步事件,做个定时检是否生成完成
var t=setTimeout(function(){
if(pic.length==newpath.length){
//把用户发送消息转发当前房间用户出去
//obj当前房对象
//message用户发送消息对象
//client_uuid发送用户,user发送用信息
wsSend(obj,message,client_uuid,user);
clearInterval(t);//停止定时
}
},100);
//收到消息就发送
}
break;
case 3://3请求在线人员
//取出当前房间人员信息
var clients=Chatnumber[id]['clients'];
var attr=[];
for(var i in clients){//取出房间所有用户信息
attr.push(clients[i]['user']);
}
var u={'state':3,'clients':attr}
ws.send(JSON.stringify(u)); //发送给当前用户
return false;
break;
case 4://4请求聊天室房间列表信息,
var attr=[];
//取出所有聊天室信息,并且过滤掉核心内容
for(var i in Chatnumber){
var chatber=new Object();
chatber['id']=Chatnumber[i]['id'];//房间id
chatber['pic']=Chatnumber[i]['pic'];//房间封面
chatber['title']=Chatnumber[i]['title'];//房间标题
chatber['miaoshu']=Chatnumber[i]['miaoshu'];//房间描述
chatber['renshu']=Chatnumber[i]['renshu'];//能够容多少人
chatber['ge']=Chatnumber[i]['clients'].length;//在线多少人
attr.push(chatber);
}
var u={'state':4,'attr':attr}
ws.send(JSON.stringify(u)); //发送数据
return false;
break;
}
console.log('房间号'+id);
});
//当有用户关掉事件,触发
ws.on('close',function(data){
dataIndex -= 1;
//获取用户id,
var id=ws.id;
if(!Chatnumber[id]){return false;}//如果房间不存时,不删除对象
var uid=ws.uid;//获取用户uid
var clients=Chatnumber[id]['clients'];
for(var i in clients){
if(clients[i]['uid']==uid){
clients.splice(i,1);//删除离开用户ws
break;
}
}
console.log('在线总用户:'+dataIndex);
});
});
}
function wsSend(data,message,uid,user){//发送当前房间所有人发送
//当前房间用户组(clients)循环发送消息,就是给房间所有用户发一遍消息
for(var i=0;i<data.clients.length;i++){
var clientSocket = data.clients[i].ws;
if(clientSocket.readyState=== 1){//检查用户是否连接
//发送消息
clientSocket.send(JSON.stringify({
'state':2,
'obj':message,
'uid':uid,
'user':user
}));
}
}
}
//服务关掉执行事件
process.on('exit', function(){
console.log('关闭'); //文件被保
});
//监听服务器ctrl+c事件,当服务器挂把时把Chatnumber聊天房间信息储存起来
//并且生成文件chat.txt,等下次再运行,重新加载文件,防止聊天室房间信息丢掉
process.on('SIGINT', function () {
var objcc={};
for(var i in Chatnumber){
var obja={};
obja['id']=Chatnumber[i]['id'];
obja['pic']=Chatnumber[i]['pic'];
obja['title']=Chatnumber[i]['title'];
obja['miaoshu']=Chatnumber[i]['miaoshu'];
obja['renshu']=Chatnumber[i]['renshu'];
obja['pw']=Chatnumber[i]['pw'];
obja['clients']=[];
obja=JSON.stringify(obja);
objcc[i]=obja;
}
var c=JSON.stringify(objcc);
fs.writeFile('chat.txt',c, function (err) {
if (err) throw err;
console.log('保存成功'); //文件被保存
process.exit(0);
});
});
可能有一些代码不合理设计,欢迎大家指出。
需要交流和讨论,加QQ群 :293851491