webSocket简介
webSocket是一种可在单个TCP连接上进行全双工通讯的网络传输协议,同样是HTML 5规范的组成部分之一。webSocket在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了
websocket的特点
建立在 TCP 协议之上,服务器端的实现比较容易
与 HTTP 协议有着良好的兼容性。默认端口也是 80 和 443 ,并且握手阶段采用 HTTP 协议,能通过各种 HTTP 代理服务器
数据格式比较轻量,性能开销小,通信高效
可以发送文本,也可以发送二进制数据
没有同源限制,客户端可以与任意服务器通信
协议标识符是ws(如果加密,则为wss),服务器网址就是 URL
websocket握手建立连接过程
来自客户端的握手看起来像如下形式:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin:
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Connection 必须设置 Upgrade,表示客户端希望连接升级;Upgrade字段必须设置 WebSocket,表示希望升级到 WebSocket 协议
来自服务器的握手看起来像如下形式:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
客户端可以在控制台 -network-ws下看到 WebSocket 消息,可以看到,客户端发起的websocket连接报文类似http报文:
如果服务端支持 websocket,会在响应头中返回相同的信息,并且连接状态置为101(协议切换成功)
一旦客户端和服务器都发送了它们的握手,且如果握手成功,接着开始数据传输部分
websocket客户端的API
构造函数
WebSocket(url[, protocols])
const ws = new WebSocket(ws://localhost:8080/websocket);
协议标识符,根据window.location.protocol是http还是https确定是用ws还是wss
常量
ws.readyState(只读)表示当前的链接状态
l CONNECTING:值为0,表示正在连接
l OPEN:值为1,表示连接成功,可以通信了
l CLOSING:值为2,表示连接正在关闭
l CLOSED:值为3,表示连接已经关闭,或者打开连接失败
属性
(1)WebSocket.binaryType - DOMString
使用二进制的数据类型连接。取值应当是"blob"或者"arraybuffer"。"blob"表示使用DOM Blob 对象,而"arraybuffer"表示使用 ArrayBuffer 对象
(2)WebSocket.bufferedAmount (只读)- unsigned long
未发送至服务器的字节数。调用 send()) 方法将多字节数据加入到队列中等待传输,但是还未发出。该值会在所有队列数据被发送后重置为 0。而当连接关闭时不会设为0。如果持续调用send(),这个值会持续增长
(3)WebSocket.extensions (只读)- DOMString
服务器选择的扩展。目前这个属性只是一个空字符串,或者是一个包含所有扩展的列表
(4)WebSocket.onclose - EventListener
用于指定连接关闭后的回调函数。当 WebSocket 对象的readyState 状态变为 CLOSED 时会触发该事件。这个监听器会接收一个叫close的 CloseEvent 对象
(5)WebSocket.onerror - EventListener
用于指定连接失败后的回调函数。会接受一个名为“error”的event对象
(6)WebSocket.onmessage - EventListener
用于指定当从服务器接收到信息时的回调函数。这个Listener会被传入一个名为"message"的 MessageEvent 对象
(7)WebSocket.onopen - EventListener
用于指定连接成功后的回调函数。当readyState的值变为 OPEN 的时候会触发该事件。该事件表明这个连接已经准备好接受和发送数据。这个监听器会接受一个名为"open"的事件对象
(8)WebSocket.protocol (只读)- DOMString
服务器选择的下属协议。这个属性的取值会被取值为构造函数传入的protocols参数
(9)WebSocket.readyState(只读)
当前的链接状态
(10)WebSocket.url (只读)
WebSocket 的绝对路径。传入构造器的URL
方法
WebSocket.close([code[, reason]]) 关闭当前链接
code 可选:
一个数字值表示关闭连接的状态号,表示连接被关闭的原因。如果这个参数没有被指定,默认的取值是1000 (表示正常连接关闭)。请看 CloseEvent 页面的 list of status codes来看默认的取值
reason 可选:
一个可读的字符串,表示连接被关闭的原因。这个字符串必须是不长于123字节的UTF-8 文本(不是字符)
WebSocket.send(data) 要发送到服务器的数据。websocket会对要传输的数据进行排队
示例
const ws = new WebSocket(ws://localhost:8818);
ws.onopen = function(e) {
console.log("连接服务器成功");
}
ws.onclose = function(e) {
console.log("服务器关闭");
}
ws.onerror = function() {
console.log("连接出错");
}
ws.onmessage = function(e){
const time = new Date();
console.log(time+"的消息:"+e.data);
}
websocket心跳检测&断线重连
为了保证连接稳定,需要考虑一些异常情况,如网络波动导致连接中断,服务器超时等
1、心跳检测
WebSocket 为了保持客户端、服务端的实时双向通信,需要确保客户端、服务端之间的 TCP 通道保持连接没有断开。然而,对于长时间没有数据往来的连接,如果依旧长时间保持着,可能会浪费包括的连接资源。但不排除有些场景,客户端、服务端虽然长时间没有数据往来,但仍需要保持连接。这个时候,可以采用心跳来实现。心跳检测即客户端定时向服务端发送心跳消息,保持连接稳定
2、断线重连
断线重连即发送消息前,检测连接状态,若连接中断,尝试n次连接
websocket的特点
location /websocket {
proxy_pass :port; # websocket服务器
proxy_http_version 1.1; # http协议切换
proxy_set_header Host $host; # 保留源信息
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade; # 请求协议升级
proxy_set_header Connection $connection_upgrade;
}
websocket服务端的实现
Node的 实现方式有以下几种。
l Socket.IO
lWebSockets
l WebSocket-Node
l ws
其中socket.io是基于 Node 的实时应用程序框架,对比原生 webSocket,封装了更多通用能力,且在不支持webSocket的浏览器上,可以降级为轮询方式通信。但是,其要求前后端必须统一,即后端使用 socket.io 则前端必须使用 socket.io-client 对应
应用场景
基于websocket的实时通信的特点,经常能看到其广泛的应用场景,比如:
· 告警弹幕
· webssh
· 比赛排行榜实时更新