使用 Socket.IO 开发聊天室
前言
Socket.IO 是一个用来实现实时双向通信的框架,其本质是基于 WebSocket 技术。
我们首先来聊聊 WebSocket 技术,先设想这么一个场景:
· 用户小A,打开了某个网站的充值界面,该界面上有一个付款的二维码。
· 当小A 用某宝的 APP 扫码付款之后,网页要自动跳转到付款成功的界面。最简单的方法就是网页每隔一段时间就请求一次服务器——“怎么样?那货付款没有?”,“怎么样?还没付吗?”,“怎么样?这次总该付了吧”。
· 当接收到服务端返回确认付款的标识后,页面再进行跳转。
这种定时对服务端发送 HTTP 请求的技术也被称为“轮询”。轮询的缺点也显而易见,短时间内的多次访问无疑会对服务器造成很大压力。
后来,人们发明了长轮询技术。这与短轮询的区别在于,每次浏览器请求服务器后,服务器并不会立即返回“用户还未付款”的结果,而是一直将 HTTP 保持在挂起状态,只有当用户付款后才会返回给浏览器 “用户已经付款” 的结果。当然,如果用户在规定时间内仍未付款还是会断开此次连接,之后浏览器再开始发送下一轮的长连接。相比短轮询,长轮询有了一定的优势,但这还是不够好。直到 HTML5 里 WebSocket 技术的诞生。
WebSocket,即 Web 浏览器与 Web 服务器之间的全双工通信标准。最初 WebSocket 只是作为 HTML5 标准的一部分,而后来却逐渐变成了独立的协议标准。一旦浏览器与服务器建立起 WebSocket 协议的通信连接,之后所有的通信都依靠该协议进行。不论是服务器还是浏览器,任何一方都能向对方发送报文。通信过程中可相互发送 JSON、HTML或图片等任意格式的数据。
关于 WebSocket 的原生 API 如何使用,本文不赘述了。 这里主要聊聊关于 Socket.IO 这个库的使用方式。Socket.IO 与 ws 等其他基于 WebSocket 通信的库相比,它的好处在于,当浏览器支持 WebSocket 技术时它能正常使用 WebSocket 来工作,当浏览器不支持 WebSocket 时,它能平稳退化成轮询进行工作。
首先放出自己做的聊天室 DEMO 源码,将源码克隆到本地,执行下面两个命令:
npm install
npm start
接着用浏览器访问 localhost:8000 即可,实际界面如下图:

Socket.IO 在客户端与服务端二者均有一套 API,我们举几个常用的进行说明。
服务端
new Server
因为 WebSocket 协议是建立在 HTTP 协议之上的,所以在创建 WebSocket 服务时需要调用 http 模块并调用其下的 createServer 方法,将生成的 server 作为参数传入 socket.io 的方法中。
var server = require('http').createServer(),
io = require('socket.io')(server);
server.listen(8000);
io.onconnection(socket)
io 的 connection 事件表示客户端与服务器成功建立连接,它会接收一个回调函数,该回调函数会接收一个 socket 参数。
io.on('connection', (socket) => {
console.log(socket);
});
io.emit(EventName, param1, param2...)
io.emit 方法用于向服务器发送消息,其第一个参数表示自定义的数据名,后面表示需要配合事件传入的参数。
io.on('connection', (socket) => {
io.emit('server message', {msg: 'Hello World.'})
});
socket.on(EventName, callback)
socket.on 方法用于接收客户端发送来的消息,EventName 参数为客户端自定义的事件名,callback 为回调函数,回调函数接收的参数即客户端传递来的参数。
io.on('connection', (socket) => {
socket.on('client message', (data) => {
console.log(data);
});
});
socket.broadcast.emit()
socket.broadcast.emit() 方法表示向除了自己以外的客户端发送消息。举个例子,当我们输入 “Message” 点击发送,只需要将 “Message” 通过服务器发送给其他客户端用于显示,而本地只需要将 “Message” 通过 js 代码添加进聊天窗口即可,而不需要经过服务器。
io.on('connection', (socket) => {
socket.broadcast.emit('server message', {
msg: 'Hello World.'
});
});
socket.ondisconnect
socket 的 disconnect 事件表示客户端与服务端断开连接。
io.on('connection', (socket) => {
socket.on('disconnect', () => {
console.log('连接已断开...');
});
});
客户端
首先需要引入 socket.io 模块中的 socket.io.js 文件。
<!Doctype HTML>
<html>
<head>
<title>Socket.IO chat</title>
<script src="/socket.io/socket.io.js"></script>
</head>
</html>
引入成功后,就可能通过 io() 生成客户端所用的 socket 对象。
var socket = io();
socket.emit(EventName, param1, param2, .....)
socket.emit 方法用于客户端向服务端发送消息,服务端与之对应的是 socket.on 方法来接收消息。
//客户端
var socket = io();
socket.emit('client message', {
msg: 'Hello Server'
}); //服务端
io.on('connection', (socket) => {
socket.on('client message', (data) => {
console.log(data.msg); // Hello Server
});
});
socket.on(EventName)
socket.on 方法用于接收服务端发来的消息
//服务端
io.on('connection', (socket) => {
io.emit('server message', {
msg: 'Hello Client'
});
}); //客户端
var socket = io();
socket.on('server message', (data) => {
console.log(data.msg); // Hello Client
});
介绍完 Socket.IO 的 API,下面开始尝试写聊天室的 DEMO。
首先创建目录如下:

其中 server.js 中保存着服务端的代码,client 文件夹中保存着客户端代码,包括 HTML、CSS、JS、图片等。
编写 server.js 如下:
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io')(server),
port = process.env.PORT || 8000;
//通过 express 加载前端部分的静态资源文件
app.use(express.static(__dirname + '/client'));
io.on('connection', (socket) => {
//通过 socket.id 创建简易的用户名
let user = '游客' + socket.id.substring(0, 6);
//通知用户进入
io.local.emit('user conncet', user + '进入聊天室');
//接收从客户端发送来的消息,拼上消息发布者的名字后,广播给其他客户端
socket.on('client message', (data) => {
data.author = user;
//将消息广播给除自己以外的客户端
socket.broadcast.emit('server message', data);
});
//通知用户离开
socket.on('disconnect', () => {
io.local.emit('user disconnect', user + '离开聊天室');
});
});
server.listen(port, () => {
console.log('listening on %d...', port);
});
前端部分代码省略,这里只简单写一个发送消息的方法,具体的代码请参考 DEMO 源码。
var socket = io();
function sendMsg() {
var message = document.querySelector('#input');
socket.emit('client message', {
text: message,
time: new Date()
});
document.querySelector('#content').innerHTML += '<div class="msgList">'+message+'</div>';
}
如上,当运行 server.js 文件后,在浏览器地址栏中输入 localhost:8000 就可以看到聊天室的界面了。 这样我们就完成了一个简易的聊天室,它包括如下功能:
· 发送/接收消息
· 通知用户进入/离开
· 为进入聊天室的用户命名,名称唯一
有兴趣的朋友还可以尝试自行完成如下功能:
· 用户登陆
· 查看所有在线用户
· @ 功能
···
感觉你的浏览,希望能有所帮助。
使用 Socket.IO 开发聊天室的更多相关文章
- Socket.io在线聊天室
从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发.Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎.chrome浏 ...
- 使用socket.io搭建聊天室
最近在学习nodejs,需要找一些项目练练手.找来找去发现了一个聊天室的教程,足够简单,也能从中学到一些东西.下面记录我练习过程中待一些笔记. nodeJS模块 共用到了2个模块,express和so ...
- node.js + socket.io实现聊天室一
前段时间,公司打算在社区做一个聊天室.决定让我来做.本小白第一次做聊天类功能,当时还想着通过ajax请求来实现.经过经理提示,说试试当前流行的node.js 和socket.io来做.于是就上网学习研 ...
- Socket.io官方聊天室DEMO的学习笔记
照着Socket.io官方的聊天室代码敲了一遍,遇到了一个奇怪的问题: 每次点击SEND按钮的时候,都会重新刷新页面. 在点击页面的一瞬间,看到了正在加载jquery的提示, 然后以为是jquery用 ...
- 使用nodejs引用socket.io做聊天室
Server: var app = require('http').createServer(handler) , io = require('socket.io').listen(app) , fs ...
- node express+socket.io实现聊天室
参照网址:https://www.jb51.net/article/135058.htm https://www.cnblogs.com/limitcode/p/7845168.html https: ...
- 使用React、Node.js、MongoDB、Socket.IO开发一个角色投票应用的学习过程(三)
这几篇都是我原来首发在 segmentfault 上的地址:https://segmentfault.com/a/1190000005040834 突然想起来我这个博客冷落了好多年了,也该更新一下,呵 ...
- AngularJS+Node.js+socket.io 开发在线聊天室
所有文章搬运自我的个人主页:sheilasun.me 不得不说,上手AngularJS比我想象得难多了,把官网提供的PhoneCat例子看完,又跑到慕课网把大漠穷秋的AngularJS实战系列看了一遍 ...
- 我的学习笔记之node----node.js+socket.io实时聊天(2)
废话不多说,直接贴代码吧.注释很详细了. 服务端代码: /** * Created by LZX on 2015/10/7. */(function () { var d = document, w ...
随机推荐
- java线程(四)
java5线程并发库 线程并发库是JDK 1.5版本级以上才有的针对线程并发编程提供的一些常用工具类,这些类被封装在java.concurrent包下. 该包下又有两个子包,分别是atomic和loc ...
- C# Webclient 和 Httpclient如何通过iis authentication 身份验证。
前言: 该博客产生的背景是客户那边有部署网站的方法是iis windows authentication身份验证,而系统中使用Webclient来调用别的系统的方法.在此情况下,原本可以使用的功能,都 ...
- Python进阶之装饰器
函数也是对象 要理解Python装饰器,首先要明白在Python中,函数也是一种对象,因此可以把定义函数时的函数名看作是函数对象的一个引用.既然是引用,因此可以将函数赋值给一个变量,也可以把函数作为一 ...
- Centos程序最小化后,窗口标签都消失找不到窗口的问题
我是用的centos版本是CentOs 7. 在“顶部面板”或者 “底部面板” 右击选择“添加组件”),如下图所示: 在搜索框里输入“窗口列表”(window list),选中“窗口列表”即可.如下图 ...
- angular.js的ui-router总结
ui-route 先有个网址,再在这个网址下写路由 子路由的搭建 我们的布局/模板文件 index.html 我们通过建立一个主文件来引入我们所需要的所有资源以开始我们的项目 ,这里 ...
- 连锁反应confirm
<script> function del(){ var flag = confirm("你真要删除么?"); if( flag ){ alert("我已被你 ...
- Linux Academy Learn Notes
Linux Essentials Certification Globbing ls ?.txt --- ? stands for one character while * means one or ...
- Java基础知识二次学习-- 第一章 java基础
基础知识有时候感觉时间长似乎有点生疏,正好这几天有时间有机会,就决定重新做一轮二次学习,挑重避轻 回过头来重新整理基础知识,能收获到之前不少遗漏的,所以这一次就称作查漏补缺吧!废话不多说,开始! 第一 ...
- (HTTPS)web 项目如何实现https
HTTPS实际是SSL over HTTP, 该协议通过SSL在发送方把原始数据进行加密,在接收方解密,因此,所传送的数据不容易被网络黑客截获和破解.本文介绍HTTPS的三种实现方法.方法一 静态超链 ...
- 走进javascript——数组的那些事
Array构造器 如果参数只有一个并且是Number类型,那么就是指定数组的长度,但不能是NaN,如果是多个会被当做参数列表. new Array(12) // (12) [undefined × 1 ...