【星课堂】一文带你了解webSocket

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

· 比赛排行榜实时更新