websocket简介
参考文档:菜鸟教程 HTML5 WebSocket
WebSocket 教程 - 阮一峰的网络日志
nodejs里面的ws模块:ws: a Node.js WebSocket library
WebSocket - Web API 接口参考 | MDN
简单来说,websocket 实时通信 全双工 一次握手,就可以建立持久性的连接,而且可以双向通信。
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
Ajax 轮询与WebSocket 对比:
现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
聊天室小例子
客户端:index.html,实例化websocket对象,传入url地址,与服务端开启连接
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="msglist">
<!--用户聊天区-->
</div>
<textarea name="" id="msg" cols="30" rows="10">
<!--发送消息的窗口-->
</textarea>
<button id="btn">留言</button>
<script>
var $btn = document.querySelector("#btn");
var $msg = document.querySelector("#msg");
var $list = document.querySelector("#msglist");
// http=>new Websocket('ws://***')
// https=>new Websocket('wss://***') 不能是ip
// 实例化一个websocket,传一个url的地址 相当于和服务端开启了连接
// 注意用的是WebSocket 协议
var ws = new WebSocket("ws://localhost:8099");
// 封装一个函数,处理websocket的几个回调函数
function wsEvent() {
ws.onmessage = (msg) => {
//数据的接收 用于指定从服务器接收到信息时的回调函数
console.log(msg);//MessageEvent
$list.innerHTML+=msg.data+'<br>';
}
ws.onopen = () => {
// 用于连接成功之后的回调函数
console.log("open 。。。")
}
ws.onclose = () => {
// 用于指定连接关闭之后的回调函数
console.log("close 。。。")
reconnect();//关闭重连
}
ws.onerror = () => {
console.log("error 。。。")
reconnect();//出现异常重新连接服务器
}
}
wsEvent();
$btn.addEventListener("click", () => {
// 点击button,把文本域中的数据的发送到服务端 websocket
ws.send($msg.value);
})
// 心跳
// 重连服务器
function reconnect() {
// 首先判断状态
if (ws.readyState === 2 || ws.readyState === 3) {
// 然后重新创建ws,重新连接服务器
var ws = new WebSocket("ws://localhost:8099");//实例化一个websocket,传一个url的地址
wsEvent();
}
}
</script>
</body>
</html>
服务端:websocket.js
nodejs里面的ws模块:ws: a Node.js WebSocket library
安装ws模块:yarn add ws(记得先生成package.json文件:npm init -y ,不然看不到安装成功的信息)
const ws = require('ws');
var websocketServer = new ws.Server({ port: 8099 });//指定端口,host为默认本地的localhost
// 所有的客户端列表
var clientList={};
var id=0;//登录的客户id号,简单模拟
// 监听一些事件 链接上了 建立连接
websocketServer.on('connection', (wsClient) => {// wsClient客户端
wsClient.id=id++;//只要增加链接,id号统计就自增
clientList[id]=wsClient;
console.log("connection...")
wsClient.send("welcome to back");
wsClient.on('message', (msg) => {
console.log(msg);
// 我们收到一个客户端的信息,就通知给所有的客户端
boardcast(wsClient.id+":"+msg);
})
// 用户关闭服务时的处理,wsClient退出时的事件
wsClient.on('close',()=>{
boardcast(wsClient.id+"下线");
delete clientList[wsClient.id];//把已下线用户信息清除
})
// wsClient.on('error')
// 不同的事件回调函数有不同的作用
})
// 做一个广播的通知,通知给所有客户端(遍历用户客户端列表里的所有用户,向每个用户发送信息)
function boardcast(message){
for(let obj in clientList){
clientList[obj].send(message);
}
}
(注意:参数传的越多,代码耦合性越高)
结果:
客户0、1、2依次上线,并发送信息,每个客户都能收到;后来客户2下线,每个客户都能收到通知。
这样就实现了一个服务器主动推送信息的功能。
服务端,用户0上线,触发connection事件,打印连接证明,在页面点击按钮发送消息,服务端接收到,并广播给所有客户端;
打印了三次连接,说明有三个客户端上线,后来客户端2下线了,服务端也把客户端2下线信息广播给所有客户端。
这个例子实现的两个功能:心跳、广播
心跳的概念:
如果服务器断开了,客户端刷新页面,就能重新连接;
如果想要解决这个问题,使服务端断开,客户端不用刷新,就能重新连接,
可以使用判断心跳,也就是通过判断ws.readyState状态来做是否重启连接的操作。
ws.readyState判断状态-----WebSocket - Web API 接口参考 | MDN
// 心跳
// 重连服务器
function reconnect() {
// 首先判断状态
if (ws.readyState === 2 || ws.readyState === 3) {
// 然后重新创建ws,重新连接服务器
var ws = new WebSocket("ws://localhost:8099");//实例化一个websocket,传一个url的地址
wsEvent();
}
}
广播:
然后我们现在想做个广播通知的功能,用户下线的时候给所有客户端提醒。
// 遍历用户客户端列表里的所有用户,向每个用户发送信息
function boardcast(message){
for(let obj in clientList){
clientList[obj].send(message);
}
}