关于网络传输协议:网络协议之WebSocket的消息格式

49次阅读

共计 3637 个字符,预计需要花费 10 分钟才能阅读完成。

简介

咱们晓得 WebSocket 是建设在 TCP 协定根底上的一种网络协议,用来进行客户端和服务器端的实时通信。十分的好用。最简略的应用 WebSocket 的方法就是间接应用浏览器的 API 和服务器端进行通信。

本文将会深入分析 WebSocket 的音讯交互格局,让大家得以明确,websocket 到底是怎么工作的。

WebSocket 的握手流程

咱们晓得 WebSocket 为了兼容 HTTP 协定,是在 HTTP 协定的根底之上进行降级失去的。在客户端和服务器端建设 HTTP 连贯之后,客户端会向服务器端发送一个降级到 webSocket 的协定,如下所示:

GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

留神,这里的 HTTP 版本必须是 1.1 以上。HTTP 的申请办法必须是 GET

通过设置 Upgrade 和 Connection 这两个 header,示意咱们筹备降级到 webSocket 了。

除了这里列的属性之外,其余的 HTTP 自带的 header 属性都是能够承受的。

这里还有两个比拟特地的 header,他们是 Sec-WebSocket-Version 和 Sec-WebSocket-Key。

先看一下 Sec-WebSocket-Version,它示意的是客户端申请的 WebSocket 的版本号。如果服务器端并不明确客户端发送的申请,则会返回一个 400 (“Bad Request”),在这个返回中,服务器端会返回失败的信息。

如果是不懂客户端发送的 Sec-WebSocket-Version,服务器端同样会将 Sec-WebSocket-Version 返回,以告知客户端。

这里要特地关注的一个 header 字段就是 Sec-WebSocket-Key。咱们接下来看一下这个字段到底有什么用。

当服务器端收到客户端的申请之后,会返回给客户端一个响应,通知客户端协定曾经从 HTTP 降级到 WebSocket 了。

返回的响应可能是这样的:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

这里的 Sec-WebSocket-Accept 是依据客户端申请中的 Sec-WebSocket-Key 来生成的。具体而言是将客户端发送的 Sec-WebSocket-Key 和 字符串 ”258EAFA5-E914-47DA-95CA-C5AB0DC85B11″ 进行连贯。而后应用 SHA1 算法求得其 hash 值。

最初将 hash 值进行 base64 编码即可。

当服务器端返回 Sec-WebSocket-Accept 之后,客户端能够对其进行校验,已实现整个握手过程。

webSocket 的音讯格局

之所以要应用 webSocket 是因为 client 和 server 能够随时随地发送音讯。这是 websocket 的神奇所在。那么发送的音讯是什么格局的呢?咱们来具体看一下。

client 和 server 端进行沟通的音讯是以一个个的 frame 的模式来传输的。frame 的格局如下:


      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-------+-+-------------+-------------------------------+
     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
     | |1|2|3|       |K|             |                               |
     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
     |     Extended payload length continued, if payload len == 127  |
     + - - - - - - - - - - - - - - - +-------------------------------+
     |                               |Masking-key, if MASK set to 1  |
     +-------------------------------+-------------------------------+
     | Masking-key (continued)       |          Payload Data         |
     +-------------------------------- - - - - - - - - - - - - - - - +
     :                     Payload Data continued ...                :
     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
     |                     Payload Data continued ...                |
     +---------------------------------------------------------------+

MASK 示意的是音讯是否是被编码过的,对于从 client 过去的音讯来说,MASK 必须是 1。如果 client 发送给 server 端的音讯,MASK 不为 1,则 server 须要断开和 client 的连贯。然而 server 端发送给 client 端的音讯,MASK 字段就不须要设置了。

RSV1- 3 是扩大的字段,能够疏忽。

opcode 示意怎么去解释 payload 字段。payload 就是理论要传递的音讯。0x0 示意持续,0x1 示意文本,0x2 示意二进制,其余的示意管制字段。

FIN 示意是否是音讯的最初一个 frame。如果是 0,示意该音讯还有更多的 frame。如果是 1 示意,该 frame 是音讯的最初一部分了,能够对音讯进行解决了。

为什么须要 Payload len 字段呢?因为咱们须要晓得什么时候进行接管音讯。所以须要一个示意 payload 的字段来对音讯进行具体的解决。

怎么解析 Payload 呢?这个就比较复杂。

  1. 首先读取 9 -15 bits,将其解析为无符号整数。如果其小于 125,那么这个就是 payload 的长度,完结。如果是 126,那么就去到第二步。如果是 127,那么就去到第三步。
  2. 读取下一个 16 bits,而后将其解析为无符号整数,完结。
  3. 读取下一个 64 bits。将其解析为符号整数。完结。

如果设置了 Mask,那么读取下 4 个字节,也就是 32bits。这个是 masking key。当数据读取结束之后,咱们就获取到了编码过后的 payload:ENCODED, 和 MASK key。要解码的话,其逻辑如下:

var DECODED = "";
for (var i = 0; i < ENCODED.length; i++) {DECODED[i] = ENCODED[i] ^ MASK[i % 4];

FIN 能够和 opcode 一起配合应用,用来发送长音讯。

FIN= 1 示意,是最初一个音讯。0x1 示意是 text 音讯,0x2 是 0,示意是二净值音讯,0x0 示意音讯还没有完结,所以 0x0 通常和 FIN=0 一起应用。

Extensions 和 Subprotocols

在客户端和服务器端进行握手的过程中,在规范的 websocket 协定根底之上,客户端还能够发送 Extensions 或者 Subprotocols。这两个有什么区别呢?

首先这两个都是通过 HTTP 头来设置的。然而两者还是有很大的不同。Extensions 能够对 WebSocket 进行管制,并且批改 payload,而 subprotocols 只是定义了 payload 的构造,并不会对其进行批改。

Extensions 是可选的,而 Subprotocols 是必须的。

你能够将 Extensions 看做是数据压缩,它是在 webSocket 的根底之上,对数据进行压缩或者优化操作,能够让发送的音讯更短。

而 Subprotocols 示意的是音讯的格局,比方应用 soap 或者 wamp。

子协定是在 WebSocket 协定根底上倒退进去的协定,次要用于具体的场景的解决,它是是在 WebSocket 协定之上,建设的更加严格的标准。

比方,客户端申请服务器时候,会将对应的协定放在 Sec-WebSocket-Protocol 头中:

GET /socket HTTP/1.1
...
Sec-WebSocket-Protocol: soap, wamp

服务器端会依据反对的类型,做对应的返回,如:

Sec-WebSocket-Protocol: soap

总结

本文解说了 webSocket 音讯交互的具体格局,能够看到很多弱小性能的协定,都是由最最根本的构造组成的。

本文已收录于 http://www.flydean.com/07-websocket-message/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!

正文完
 0