WebSocket

介绍

RFC 6455 规范中描述的 WebSocket 协议提供了一种通过长连接在浏览器和服务器之间交换数据的方法。 数据可以作为“数据包”双向传递,而不会中断连接并且不需要额外的 HTTP 请求。

WebSocket 特别适用于需要持续数据交换的服务,例如 网络游戏、实时交易系统等。

简单实例

要打开 websocket 连接,我们需要使用 url 中的特殊协议 ws 创建新的 WebSocket:

let socket = new WebSocket("ws://127.0.0.1:8001");

还有加密的 wss:// 协议。 这就像 websocket 的 HTTPS。
一旦创建了socket,我们就应该监听它上面的事件。 总共有4个事件:

  • open – 连接建立
  • message – 消息发送
  • error – 错误处理
  • close – 连接关闭
    如果我们想发送消息,可以使用: socket.send(data) ,下面是一个简单实例基于js:
let socket = new WebSocket("wss://127.0.0.1:8001/websocket/demo/hello");

socket.onopen = function(e) {
  alert("[open] Connection established");
  alert("Sending to server");
  socket.send("My name is John");
};

socket.onmessage = function(event) {
  alert(`[message] Data received from server: ${event.data}`);
};

socket.onclose = function(event) {
  if (event.wasClean) {
    alert(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
  } else {
    // e.g. server process killed or network down
    // event.code is usually 1006 in this case
    alert('[close] Connection died');
  }
};

socket.onerror = function(error) {
  alert(`[error]`);
};

websocket创建

new WebSocket(url)后,它会立即开始连接。
在连接期间,浏览器(headers)询问服务器:“是否支持Websocket ?” 如果服务器响应“是”,那么会话将继续在WebSocket 协议中进行,非HTTP。
在这里插入图片描述
下面一个简单的请求header信息

GET /chat
Host: javascript.info
Origin: https://127.0.0.1:8001
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
Sec-WebSocket-Version: 13
  • Origin – 客户端页面的来源,例如https://127.0.0.1:8001。 WebSocket 对象本质上是跨域的。 没有特殊的标题或其他限制。 旧服务器无论如何都无法处理 WebSocket,因此不存在兼容性问题。 但是 Origin 标头很重要,因为它允许服务器决定是否与该网站通信WebSocket
  • Connection: Upgrade——表示客户端想要更改协议。
  • Upgrade:websocket——请求的协议是“websocket”。
  • Sec-WebSocket-Key – 浏览器生成的随机密钥,用于确保服务器支持 WebSocket 协议。 防止代理缓存任何后续通信是随机的。
  • Sec-WebSocket-Version - WebSocket 协议版本

如果服务端支持WebSocket,它会发生相应码101:

101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g=

这里的 Sec-WebSocket-Accept 是 Sec-WebSocket-Key,使用特殊算法重新编码。 浏览器能够解析该编码, 来确认服务端支持该WebSocket协议。
之后,使用 WebSocket 协议传输数据,我们很快就会看到它的结构(“frames”)。 而不是传统意义的 HTTP

扩展和子协议

请求header中可以增加: Sec-WebSocket-Extensions 和 Sec-WebSocket-Protocol

let socket = new WebSocket("wss://127.0.0.1:8001/chat", ["soap", "wamp"]);

请求如下

GET /chat
Host: javascript.info
Upgrade: websocket
Connection: Upgrade
Origin: https://127.0.0.1:8001
Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: deflate-frame
Sec-WebSocket-Protocol: soap, wamp

相应

101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g=
Sec-WebSocket-Extensions: deflate-frame
Sec-WebSocket-Protocol: soap
  • Sec-WebSocket-Extensions:deflate-frame 表示浏览器支持数据压缩。 扩展是与传输数据相关的东西,是扩展 WebSocket 协议的功能。 Sec-WebSocket-Extensions 由浏览器自动发送,其中包含它支持的所有扩展的列表。
  • Sec-WebSocket-Protocol:soap, wamp 意味着我们不仅要传输任何数据,还要传输 SOAP 或 WAMP(“The WebSocket Application Messaging Protocol”)协议中的数据。 WebSocket 子协议在 IANA 目录中注册。 因此,此headers描述了我们将要使用的数据格式。

数据传输

WebSocket 通信由“frames”——数据片段组成,可以从任何一方发送,并且可以有以下几种:

  • text frames ——包含各方相互发送的文本数据。
  • binary data frames ——包含各方相互发送的二进制数据。
  • ping/pong frames —— 用于检查连接,从服务器发送,浏览器自动响应这些。
  • connection close frame —— 和其他一些服务框架。

在浏览器中,我们只直接使用文本或二进制帧
WebSocket .send() 方法可以发送文本或二进制数据
调用 socket.send(body) 允许使用字符串或二进制格式的正文,包括 Blob、ArrayBuffer 等。无需设置:以任何格式发送即可。

当我们收到数据时,文本总是以字符串的形式出现。对于二进制数据,我们可以在 Blob 和 ArrayBuffer 格式之间进行选择。

这是由 socket.binaryType 属性设置的,默认为“blob”,因此二进制数据以 Blob 对象的形式出现。

socket.binaryType = "arraybuffer";
socket.onmessage = (event) => {
  // event.data is either a string (if text) or arraybuffer (if binary)
};

发送限制

想象一下,我们的应用程序正在生成大量要发送的数据。 但是用户的网络连接速度很慢。

我们可以一次又一次地调用 socket.send(data)。 但是数据将被缓冲(stored)在内存中,并仅在网络速度允许的情况下以最快的速度发送出去。

socket.bufferedAmount 属性存储了此时有多少字节保持缓冲,等待通过网络发送。

setInterval(() => {
  if (socket.bufferedAmount == 0) {
    socket.send(moreData());
  }
}, 100);

连接关闭

通常,当一方想要关闭连接时(浏览器和服务器具有相同的权限),他们会发送一个带有数字代码和文本原因的“connection close frame”。

socket.close([code], [reason]);
  • code 一个特殊的 WebSocket code(可选)
  • reason 关闭原因(可选)
socket.close(1000, "Work complete");

socket.onclose = event => {
  // event.code === 1000
  // event.reason === "Work complete"
  // event.wasClean === true (clean close)
};

最常见的代码值:

  • 1000 - 默认的正常关闭(如果没有提供代码则使用)
  • 1006 - 无法手动设置此类代码,表示连接丢失(无关闭帧)
  • 1001 - 服务器正在关闭,或浏览器离开页面
  • 1009 – 消息太大而无法处理
  • 1011 - 服务器上出现意外错误

连接状态

要获取连接状态,另外还有带有值的 socket.readyState 属性:

  • 0 – “CONNECTING”:连接尚未建立,
  • 1 – “OPEN”:打开并连接,
  • 2 – “CLOSING”:连接正在关闭,
  • 3 – “CLOSED”:连接已关闭。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值