本文始发于我的个人网站:www.jianfengke.com/
WebSocket是啥
Websocket是一个持久化的网络通信协议,可以在单个 TCP 连接上进行全双工通讯,没有了Request和Response的概念,两者地位完全平等,连接一旦建立,客户端和服务端之间实时可以进行双向数据传输.
WebSocket跟Http区别与联系
- HTTP是非持久的协议,客户端想知道服务端的处理进度只能通过不停地使用 Ajax进行轮询或者采用 long poll 的方式来,但是前者对服务器压力大,后者则会因为一直等待Response造成阻塞
- websocket是独立于HTTP的一种协议,但是websocket必须依赖 HTTP 协议进行一次握手(在握手阶段是一样的),握手成功后,数据就直接从 TCP通道传输,与 HTTP 无关
WebSocket应用
得益于Websocket全双工通信机制,WebSocket可以做弹幕、消息订阅、多玩家游戏、协同编辑、股票基金实时报价、视频会议、在线教育、聊天室等应用实时监听服务端变化。
快速上手WebSocket用法,包括客户端与服务端
首先,我们想搞个这样的东西:
- 客户端(前端页面,可多个,代表不同用户)与服务器建立socket连接,建立连接时客户端及服务端都有反应(如输出:加入websocket连接)
- 客户端发送消息,服务端接受到信息后,发送特定的消息返回对应客户端
- 任一客户端发送消息,服务端接受到信息后,广播到所有客户端
首先我们来实现功能1
我们借助的工具很简单,一个socket包: ws
我们从头安装来应该是这样:
新建文件夹,如命名socket-test,进入该目录
mkdir socket-test
cd socket-test
建立index.js文件,用于启动服务端socket服务
touch index.js
初始化npm,并安装ws
npm init -y
npm i ws
根据ws的文档,快速启动一个websocket服务,如指定启动在9003端口
const WebSocket = require('ws');
const wss = new WebSocket.Server({
port: 9003
})
wss.on("connection", ws => { //监听到有客户端连接上该socket服务时的回调,ws的相关接口操作是针对当前发送信息的客户端
console.log('加入websocket连接')
ws.on('open', () => { //当监听到连接已开启时,给对应的客户端返回连接成功的提示
ws.send('连接已开启');
});
ws.on('message', (data) => { //连接上就开始启动对该客户端的监听,一旦有消息发送过来立马触发回调
ws.send(`你发的消息是:${data}`)
});
})
就这样,一个简易的websocket服务端就搞好了,你没看错,就这几行代码。
初始化一个客户端页面:
好的现在来初始化一个客户端页面: 在同目录下建立的client1.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>客户端1</title>
</head>
<body>
</body>
<script>
let ws = new WebSocket("ws://localhost:9003")
ws.onopen = () => {
console.log('已开启')
}
ws.onmessage = event => {
console.log('客户端1收到服务端消息:', event.data)
}
ws.onclose = () => {
console.log('已关闭');
}
</script>
</html>
启动服务
好的,到现在客户端跟服务端都已经好的,分别启动吧. 启动服务端:
node index.js
或nodemon index.js(推荐)
启动客户端: 直接通过liveServer插件就可启动该页面(liveServer为vscode启动页面服务的一个插件,不懂得可自查)
现在都启动了:
服务端输出提示
客户端提示:

WebSocket实例
我们来看下客户端websocket实例都包含了啥:

WebSocket构造函数是浏览器原生接口,专用于进行websocket通信,连接方式也很简单,把服务端地址作为构造参数传进去,然后实例化便完成了websoket的连接。不了解WebSocket的可以点这里看下文档介绍以及用法:WebSocket doc
我们可观察上图实例中的一些属性与方法,可见onclose,onmessage这些已经给定义了回调方法,url属性代表当前websocket连接的地址是什么。重点要关注的是客户端如何向服务端发消息。很简单,实例有个send方法,直接把消息作为send的参数执行便可发送消息。
客户端发送消息
如现在来给服务端发个消息:
ws.send('你好鸭')
发送后服务端接收到消息后立即返回:

没错,这就是socket进行通信的基础流程,聊天室原理跟这个差不多就是一样的了
实现广播功能
如果当前有多个客户端,任一个客户端发来消息,服务端都把消息广播到所有客户端,这怎么做呢?
首先加多一个客户页面,client2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>客户端2</title>
</head>
<body>
</body>
<script>
let ws = new WebSocket("ws://localhost:9003")
ws.onopen = () => {
console.log('已开启')
}
ws.onmessage = event => {
console.log('客户端2收到服务端消息:', event.data)
}
ws.onclose = () => {
console.log('已关闭');
}
</script>
</html>
需要明确的是,默认情况下,哪个客户端实例给服务端发送了消息,服务端是可感知的,执行ws.send是也是只会针对对应的客户端发送,不会影响其他客户端。
想实现广播功能,需要对服务端进行一个小改造:
const WebSocket = require('ws');
const wss = new WebSocket.Server({
port: 9003
})
wss.on("connection", ws => { //监听到有客户端连接上该socket服务时的回调,ws的相关接口操作是针对当前发送信息的客户端
console.log('加入websocket连接')
ws.on('open', () => { //当监听到连接已开启时,给对应的客户端返回连接成功的提示
ws.send('连接已开启');
});
ws.on('message', (data) => { //连接上就开始启动对该客户端的监听,一旦有消息发送过来立马触发回调
// 取得所有连接中的 客户端
let clients = wss.clients;
//循环,发送消息至每个客户端
clients.forEach((client) => {
client.send(`你发的消息是:${data}`);
});
});
})
核心是通过wss.clients回去当前已连接的客户端实例,遍历发送消息
现在从客户端1发送消息看看客户端2能不能收到。
客户端1:
客户端2:

可见,两者都收到了服务端的广播信息 这就完成了消息的广播
结尾
经过这么一个小栗子鼓捣一下,是不是对WebSocket明白了许多?其实它的功能远不止于此,大家多去发掘,记得有啥好的实践记得推荐给我啊,加油加油。。。。
本文使用 mdnice 排版