# 简介

WebSocket 是一种和 HTTP 不同的协议。两者都位于 OSI 模型的应用层,并且都依赖于传输层的 TCP 协议,WebSocket 复用了 HTTP 的握手通道。

虽然和 HTTP 不同,但是 RFC 6455 中规定:it is designed to work over HTTP ports 80 and 443 as well as to support HTTP proxies and intermediaries(WebSocket 通过 HTTP 端口 80 和 443 进行工作,并支持 HTTP 代理和中介),从而使 WebSocket 与 HTTP 协议兼容。

WebSocket 协议的最大特点就是服务器可以主动向客户端发送信息,客户端也可以向服务器发送信息,实现了双向通信。

| 特点

* 1 连接状态

WebSocket 创建连接之后就成为一种有状态的协议,之后的通信可以省略部分状态信息。而 HTTP 请求可能需要在每个请求都携带状态信息(如身份认证等)。

* 2 实时性

由于 WebSocket 协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于 HTTP 请求需要等待客户端发起请求服务端才能响应,延迟明显更少。

* 3 开销

WebSocket 协议有着较少的控制开销。在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小。在不包含扩展的情况下,对于服务器到客户端的内容,此头部大小只有 2 至 10 字节(和数据包长度有关);对于客户端到服务器的内容,此头部还需要加上额外的 4 字节的掩码。相对于HTTP 请求每次都要携带完整的头部,此项开销显著减少了。

* 4 二进制支持

WebSocket 定义了二进制帧,相对 HTTP,可以更轻松地处理二进制内容。

* 5 扩展

WebSocket 定义了扩展,用户可以扩展协议、实现部分自定义的子协议。如部分浏览器支持压缩等。

* 6 压缩

相对于 HTTP 压缩,WebSocket 在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率。

# 建立连接

WebSocket 请求通过 HTTP/1.1 协议的 101 状态码进行握手,同样包含请求报文和响应报文。
不同浏览器的 WebSocket 最大连接数量不同:

  • IE:6
  • Chrome:256
  • Firefox:200
  • Safari:1273(Mac版本)

    | 客户端:申请协议升级

    1. GET /chat HTTP/1.1
    2. Host: server.example.com
    3. Upgrade: websocket
    4. Connection: Upgrade
    5. Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    6. Origin: http://example.com
    7. Sec-WebSocket-Extensions: deflate-frame
    8. Sec-WebSocket-Protocol: soap, wamp
    9. Sec-WebSocket-Version: 13
  • Connection:该字段必须设置为Upgrade,表示客户端要升级协议。

  • Upgrade:必须设置为websocket,表示客户端要求升级到WebSocket协议。
  • Sec-WebSocket-Key:浏览器随机生成基于 Base64 的密钥。服务器基于这个密钥生成响应首部的Sec-WebSocket-Accept
  • Origin:该字段是必须的,如果缺少Origin字段,服务器需要回复 HTTP 403 状态码(禁止访问)。
  • Sec-WebSocket-Version:表示支持的 WebSocket 版本(RFC6455 要求使用的版本是 13)。如果服务端不支持该版本,会返回一个 Sec-WebSocket-Version 头,里面包含服务端支持的版本号。
  • Sec-WebSocket-Protocol:表示不仅要传输任何数据,还要传输 SOAP 或 WAMP(“The WebSocket Application Messaging Protocol”)协议中的数据。
  • Sec-WebSocket-Extensions:由浏览器自动发送,其中包含其支持的所有扩展的列表。

    | 服务器:响应协议升级

    1. HTTP/1.1 101 Switching Protocols
    2. Upgrade: websocket
    3. Connection: Upgrade
    4. Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
    5. Sec-WebSocket-Extensions: deflate-frame
    6. Sec-WebSocket-Protocol: soap
  • Sec-WebSocket-Accept:服务器通过请求报文中的Sec-WebSocket-Key加密过后生成的值,浏览器通过这个值确保请求和响应对应,同样可以防止恶意连接或避免普通 HTTP 请求被误认为WebSocket协议。

  • Sec-WebSocket-Protocol:表示服务器仅支持所请求的子协议中的 SOAP。
  • Sec-WebSocket-Extensions:表示服务器支持客户端请求中的扩展。

    * Sec-WebSocket-Accept 的生成过程

  1. 将请求报文中的Sec-WebSocket-Key加上一个特殊的字符串。
  2. 计算 SHA-1 摘要,然后进行 Base64 编码,结果就为Sec-WebSocket-Accept头的值。
    1. toBase64(sha1(Sec-WebSocket-Key + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11))
    ```javascript const crypto = require(‘crypto’); const magic = ‘258EAFA5-E914-47DA-95CA-C5AB0DC85B11’; const secWebSocketKey = ‘w4v7O6xFTi36lq3RNcgctw==’;

let secWebSocketAccept = crypto.createHash(‘sha1’) .update(secWebSocketKey + magic) .digest(‘base64’);

console.log(secWebSocketAccept); // Oy4NRAQ13jhfONC7bP8dTKb4PTU= ```

# 参考

  1. WebSocket-wikipedia
  2. WebSocket 教程-阮一峰的网络日志
  3. websocket-javascript.info
  4. WebSocket 是什么原理?为什么可以实现持久连接?-知乎
  5. WebSocket协议:5分钟从入门到精通