基于socket.io+express的聊天室demo
一,案例的效果图
1,刚刷新时出新用户名输入的input框,用于输入用户的用户信息
2,用户上线后,浏览器上线时的提示
3,聊天室群发消息
4,聊天室单发消息
5,聊天室发送图片
具体大家可以去我的coding克隆这个项目:socket.io+express聊天室demo
二,聊天室框架搭建
1,因为案例是基于express的demo,可以使用官网的express应用生成器生成应用。
npm install express-generator -g
2,在相应目录下生成文件
express myapp
3,进入这个应用,并安装相应依赖
cd myapp
npm install
4,紧接着运行程序
npm start // 或者 node ./bin/www
5,相应的目录结构如下
.
├── app.js
├── bin
│ └── www
├── package.json
├── public
│ ├── css
│ ├── images
│ ├── javascripts
│ ├── js
│ ├── stylesheets
│ └── stylesheets
│ ├── main.css
│ ├── style.css
│ ├── ...
├── routes
│ ├── index.js
│ └── users.js
└── views
├── error.jade
├── index.jade
└── layout.jade
三,聊天时的消息提示类
使用了插件Sco.js和bootstrap的HubSpot 弹框组件库,具体的使用这里不过多的介绍,大家可以看看官方的api或者适应你自己的消息提示插件。
四,socket.io的介绍
1,什么是socket.io
由于http是无状态的协议,所以实现聊天等通信功能非常困难,当别人发送一条消息时,服务器并不知道当前有哪些用户等着收消息,所以以前实现聊天通信功能最普遍的就是轮询机制了,客户端定期发一个请求,看看有没有人发送消息到服务器上了,如果有,服务器就将消息发给该客户端。
缺点显而易见,那么多的请求消耗了大量资源,有大量的请求其实是浪费了。
现在,我们有了WebSocket,他是HTML5的新api。 WebSocket 连接本质上就是一个 TCP 连接,WebSocket会通过http请求建立,建立后的WebSocket会在客户端和服务器端建立一个持久的连接,直到有一方主动的关闭了该连接。所以现在服务器就知道有哪些用户正在连接了,这样通讯就变得相对容易了
Socket.io实际上是WebSocket的父集,Socket.io封装了WebSocket和轮询等方法,他会根据情况选择方法来进行通讯。
2,在express整合socket.io
- 首先,在根目录新建serverchat.js
var io = require('socket.io')();
exports.listen = function(_server){
io.listen(_server);
};
- 接着在bin目录下的www文件的
require(http)
后引入serverchat.js
var io = require('../serverchat');
- 同时将io挂到我们的server下,并注释掉我们之前开启服务的
server.listen(port);
io.listen(server);
server.listen(port); //将这段删除或者注释
这里还有一个需要注意的是,我们不能使用var server = http.createServer(app);
这段代码创建一个服务了,而是需要用以下代码创建服务,否则服务启动不了。
var server = app.listen(app.get('port'), function() {
debug('node_chat server listening on port ' + server.address().port);
});
五,socket.io的连接,断开。
1,在服务器端
serverchat.js中,我们处理相关的关于socket.io的代码
io.on('connection',function(socket){
socket.on('disconnect',function(){
});
}) // 使用这段代码进行socket的连接
这里我们要注意的是接下去我们要做的关于信息发送等操作,都是要在连接的前提下建立的,只有当我们连接了socket之后,我们才能做我们想让socket为我们做的事情。
2,在客户端中
我们在public/javascript
下建立两个文件,chat.js
、client.js
在chat.js
中我们主要做的事接受服务端请求,并通过client.js
中的关于jq的处理页面相关的方法。
这里我们大可以把所有的js写在一个文件中,但是我们分成两个写的话,会是代码更佳移动,好维护。
3,接下来在index.jade中引入这两个js
script(src='/javascripts/chat.js')
script(src='/javascripts/client.js')
这里说到的关于jade的语法,大家如果还不是特别熟的话,可以去参考jade官网,里面有详细的介绍。
六,用户登录
这里的登录是假登录,我们只是需要获取用户input
框里面输入的姓名以及用户的头像图片。
1,客户端
当用户在输入框中输入名字,确定之后,客户端会发一个信息给服务端,socket通过emit这个函数发送信息,通过on这个函数接受信息。
在client.js
中
// 用户登录
$('#btn-setName').click(function(){
var name = $('#username').val();
console.log(name);
if(checkUser(name)){
$('#username').val('');
alert('Nickname already exists or can not be empty!');
} else {
// 随机头像
var imgList = ["/images/1.jpg","/images/2.jpg","/images/3.jpg","/images/4.jpg","/images/5.jpg"];
var randomNum = Math.floor(Math.random()*5);
var img = imgList[randomNum];
// 发送到服务端的用户信息数据
var dataObj = {
name:name,
img:img
};
socket.emit('login',dataObj);
// 隐藏modal
$('#myModal').modal('hide');
$('#username').val('');
$('#msg').focus();
}
})
2,服务端
得到客户端传过来的数据,将用户信息塞入到服务端的userList,服务器将新的userList发送给各个客户端。
var userList = [];
socket.on('login', function(user){
user.id = socket.id;
userList.push(user);
io.emit('userList',userList); // 发送给所有的用户
socket.emit('userInfo',user); // 发送给自己
socket.broadcast.emit('loginInfo',user.name+"上线了。");
//发送给出自己外的用户
});
3,客户端
的chat.js
中接收userList
,客户端接受到新的userList
的时候,渲染新的用户聊天室列表,在接受到新的userInfo
的时候在列表左侧显示相应的“欢迎你,用户名”字样。
// 用户列表渲染
socket.on('userList',function(userlist){
addUser(userlist);
})
// 用户信息渲染
socket.on('userInfo',function(userObj){
//should be use cookie or session
userSelf = userObj; // 真实的登录应该把用户信息存在session里。
$('#spanuser').text('欢迎您! '+userObj.name);
})
至此,我们便完成一个简单的socket的数据的交互。
七,发送单聊与群聊
- 群聊,比较简单,我们可以通过socket广播
socket.broadcast.emit()
,发送给除自己以外的用户。
socket.on('toAll',function(msgObj){
socket.broadcast.emit('toAll',msgObj);
});
- 单聊,刚刚我们讲过
socket.emit()
是发送信息给自己,每一个socket有自己的id,我们只需要将socket的id变成我们要发送的那个用户的id,我们就能实现单聊了。
socket.on('toOne',function(msgObj){
var toSocket = _.findWhere(io.sockets.sockets,{id:msgObj.to});
toSocket.emit('toOne', msgObj);
})
上面的 -
是我们引用的 underscore
,处理数据的一个库。具体可以查看underscore中文文档,通过npm install underscore --save
安装依赖。同时我们可以通过 io.sockets.sockets
获取所有的socket
的id
。
八,如何发送图片
我们可以通过h5的api——FileReader()
,这个api会将图片转化为base64
格式的,然后就可以进行发送了,
1,客户端
//send image to all
$('#sendImage').change(function(){
if(this.files.length != 0){
var file = this.files[0];
reader = new FileReader();
if(!reader){
alert("!your browser doesn\'t support fileReader");
return;
}
reader.onload = function(e){ // 加载文件
var msgObj = {
from:userSelf,
img:e.target.result
};
socket.emit('sendImageToALL',msgObj);
addImgFromUser(msgObj,true);
};
reader.readAsDataURL(file); // 将图片转化为base64格式的
}
});
2,服务端
将信息发送给客户端,客户端转发给除了自己的其他socket用户
//sendImageToALL
socket.on('sendImageToALL',function(msgObj){
socket.broadcast.emit('sendImageToALL',msgObj);
})
3,客户端
chat.js
中接受相应的图片socket信息,
socket.on('sendImageToALL',function(msgObj){
addImgFromUser(msgObj,false);
});
在 client.js
中,将图片进行相应的dom操作,将图片渲染进去。 base64
格式的也可以通过 标签中的src进行渲染。
九,对于文章的一些说明
1,此篇文章的demo是我在学习一个socket.io视频时的demo做的,非常感谢这个老师的视频。
2,我写这篇文章的目的是希望能给没有时间去看视频学习,同时又懒得去看文档的小伙伴们一个快速了解 socket.io
制作聊天室。
3,如需要这个视频的小伙伴,可以在私信我向我要。
4,文章可能会存在很多问题,欢迎小伙伴批评指正哦