基于 socket.io+express 的聊天室 demo
一, 案例的效果图
image
1, 刚刷新时出新用户名输入的 input 框, 用于输入用户的用户信息
image
2, 用户上线后, 浏览器上线时的提示
image
3, 聊天室群发消息
image
4, 聊天室单发消息
image
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 格式的也可以通过
<img src="" />
标签中的 src 进行渲染.
九, 对于文章的一些说明
1, 此篇文章的 demo 是我在学习一个 socket.io 视频时的 demo 做的, 非常感谢这个老师的视频.
2, 我写这篇文章的目的是希望能给没有时间去看视频学习, 同时又懒得去看文档的小伙伴们一个快速了解 socket.io 制作聊天室.
3, 如需要这个视频的小伙伴, 可以在私信我向我要.
4, 文章可能会存在很多问题, 欢迎小伙伴批评指正哦
来源: http://www.jianshu.com/p/62bd521531ec