共计 2399 个字符,预计需要花费 6 分钟才能阅读完成。
1、背景
很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔由浏览器对服务器发出 HTTP 请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而 HTTP 请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。HTML5 新增的一些新协议WebSocket, 可以提供在单个 TCP 连接上 提供全双工,双向通信,能够节省服务器资源和带宽,并且能够实时进行通信。
2、WebSocket 介绍
传统的 http 也是一种协议,WebSocket 是一种协议,使用 http 服务器无法实现 WebSocket,
2.1. 浏览器支持情况
基本主流浏览器都支持
2.2. 优点
相对于 http 有如下好处:
- 1. 客户端与服务器只建立一个 TCP 连接,可以使用更少的连接。
- 2.WebSocket 服务器端可以主动推送数据到客户端,更灵活高效。
- 3. 更轻量级的协议头,减少数据传送量。
对比轮训机制
3、WebSocket 用法
我们了解 WebSocket 是什么,有哪些优点后,怎么使用呢?
3.1.WebSocket 创建
WebSocket 使用了自定义协议,url 模式与 http 略有不同,未加密的连接是 ws://,加密的连接是 wss://,WebSocket 实例使用 new WebSocket()
方法来创建,
var ws = new WebSocket(url, [protocol] );
第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议。
3.2.WebSocket 属性
当创建 ws 对象后,readyState 为 ws 实例状态,共 4 种状态
- 0 表示连接尚未建立。
- 1 表示连接已建立,可以进行通信。
- 2 表示连接正在进行关闭。
- 3 表示连接已经关闭或者连接不能打开。
Tips:在发送报文之前要判断状态,断开也应该有重连机制。
3.3.WebSocket 事件
在创建 ws 实例对象后,会拥有以下几个事件,根据不同状态可在事件回调写方法。
- ws.onopen 连接建立时触发
- ws.onmessage 客户端接收服务端数据时触发
- ws.onerror 通信发生错误时触发
- ws.onclose 连接关闭时触发
ws.onmessage = (res) => {console.log(res.data);
};
ws.onopen = () => {console.log('OPEN...');
};
ws.onclose=()=>{console.log('CLOSE...');
}
3.4.WebSocket 方法
- ws.send() 使用连接发送数据(只能发送纯文本数据)
- ws.close() 关闭连接
4、Demo 演示
了解 WebSocket 的一些 API 之后,趁热打铁,做一个小案例跑一下。
4.1.Node 服务器端
WebSocket 协议与 Node 一起用非常好,原因有以下两点:
1.WebSocket 客户端基于事件编程与 Node 中自定义事件差不多。
2.WebSocket 实现客户端与服务器端长连接,Node 基本事件驱动的方式十分适合高并发连接
创建一个 webSocket.js 如下:
const WebSocketServer = require('ws').Server;
const wss = new WebSocketServer({port: 8080});
wss.on('connection', function (ws) {console.log('client connected');
ws.on('message', function (message) {ws.send('我收到了' + message);
});
});
打开 windows 命令窗口运行
4.2.HTML 客户端
新建一个 index.html 页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webSocket 小 Demo</title>
</head>
<body>
<div class="container">
<div>
<input type="text" id="msg">
<button onclick="sendMsg()"> 发送报文 </button>
</div>
</div>
<script>
const ws = new WebSocket('ws://localhost:8080');
ws.onmessage = (res) => {console.log(res);
};
ws.onopen = () => {console.log('OPEN...');
};
ws.onclose = () => {console.log('CLOSE...');
}
function sendMsg() {let msg = document.getElementById('msg').value;
ws.send(msg);
}
</script>
</body>
打开浏览器依次输入字符 1,2,3,每次输入完点击发送报体,可见在 ws.onmessage 事件中 res.data 中返回来我们发的报文
5、问题与总结
以上只是简单的介绍了下 WebSocket 的 API 与简单用法,在处理高并发,长连接这些需求上,例如聊天室,可能 WebSocket 的 http 请求更加合适高效。
但在使用 WebSocket 过程中发现容易断开连接等问题,所以在每次发送报文前要判断是否断开,当多次发送报文时,由于服务器端返回数据量不同,返回客户端前后顺序也不同,所以需要在客户端收到上一个报文返回数据后再发送下一个报文,为了避免回调嵌套过多,通过 Promise,async ,await 等同步方式解决。关于 WebSocket 就写这么多,如有不足,欢迎多多指正!
参考资料:
《JavaScript 高级教程》
《深入检出 NodeJs》
《菜鸟教程》