WebSocket理解与应用

概念

websocket是一个网络传输协议,可以在单个tcp连接上进行全双工通信,位于OSI7层网络模型(物理层、数据链路层、网络层、传输层、会话层、表示层、应用层)中的应用层。

为什么需要websocket

传统的http协议只能由客户端发起请求,然后服务端这边才能响应请求,也就是把数据发给客户端,服务端这边没办法主动发送数据给客服端。

基于单向请求的特点,如果客户端这边想不断获取服务端状态的变化,那么就要借助轮询。常见的轮询分为两种:短轮询长轮询(Comet)。

我们可以用两段代码来直观的体现短轮询和长轮询的特点

短轮询

function polling(url) {
    
    
    let xhr = new XMLHttpRequest()
    xhr.open('get', url)
    xhr.onload = function() {
    
    ...}
    xhr.send()
}
// 每隔30s发送一次请求    
setInterval(() => {
    
    
    polling('./api/getData')
}, 30000)

长轮询

function longPolling(url) {
    
    
    let xhr = new XMLHttpRequest()
    xhr.open('get', url)
    xhr.onload = function() {
    
    
        // 请求结束后再接着发送请求
        longPolling('./api/getData')
    }
    xhr.send()
}

longPolling('./api/getData')

从上面我们其实可以看出短轮询长轮询的特点。短轮询每隔固定的时间向服务器发送请求。这种方式实时性比较差,而且很浪费带宽资源(有效请求很少)。而长轮询服务器收到请求后会将请求挂起,等请求的数据发生了变化后,再返回新的数据。长轮询解决了实时性的问题,但如果服务器这边收到多个长轮询请求会导致服务器的多个线程被挂起,进而导致服务器大量资源的浪费。

在这种情况下,HTML5定义了新的websocket协议,使得服务端可以主动向客户端发送消息,这样既可以节约带宽和服务端资源,也能够更加实时地进行通信。

机制

websocket其实也利用了http协议。websocket通过握手机制建立客户端和服务端之间的连接,而握手机制正是通过http协议完成的。

websocket连接必须由浏览器发起,浏览器会发送一个http请求。

GET ws://example.com:80/some/path HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Origin: http://localhost:3000
Sec-WebSocket-Key: client-random-string
Sec-WebSocket-Version: 13

这个请求和普通的http请求有些不同点:

  • 请求的URL是以ws://开头的
  • 请求头Upgrade: websocketConnection: Upgrade表示这个连接将要被转换为websocket连接
  • 两个websocket相关的请求头,Sec-WebSocket-Key用来标识连接,Sec-WebSocket-Version指定websocket版本

服务器收到请求后,会返回http响应。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: server-random-string

这个响应没什么好说的,唯一需要注意的就是状态码101表示协议即将被切换,即由http协议切换成Upgrade: websocket指定的websocket协议。

握手结束后,客户端和服务端之间的连接就建立起来了,后续便可以进行双向数据传输了。传输的数据支持两种格式,文本二进制数据

API

构造函数

构造函数用于新建websocket实例

let ws = new WebSocket('ws://localhost:8080');

实例属性

  • binaryType:二进制的类型(blob或者ArrayBuffer
  • bufferedAmount:未发送出去的字节数量,可以用来判断数据是否发送完毕
  • readyState
    • CONNECTING:值为0,表示正在连接。
    • OPEN:值为1,表示连接成功,可以通信了。
    • CLOSING:值为2,表示连接正在关闭。
    • CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
  • 四个回调
    • onclose:连接关闭后执行的回调
    • onerror:报错后执行的回调
    • onopen:连接成功后执行的回调
    • onmessage:收到数据后执行的回调

方法

  • close:用来关闭websocket连接
ws.close();
  • send:发送数据
if (ws.readyState !== WebSocket.OPEN) {
    
    
	console.log("连接未建立,还不能发送消息");
	return;
}
// 发送的数据可以是文本 可以是blob 可以是ArrayBuffer
ws.send('message')

const buffer = new ArrayBuffer(128);
ws.send('buffer')

const blob = new Blob([buffer]);
ws.send(blob)

事件

对应上面那四个回调

  • open
  • close
  • message
  • error

事件的回调可以通过实例的属性指定,也可以借助addEventListener绑定,addEventListener可以绑定多个回调。

参考

廖雪峰web开发-websocket篇
一篇吃透WebSocket

猜你喜欢

转载自blog.csdn.net/m0_64023259/article/details/127181178