WebSocket 简介

0、概念介绍

  • 单工通信:数据传输只允许在一个方向上传输,只能一方发送数据,另一方接收数据并发送。
  • 半双工:数据传输允许两个方向上的传输,但在同一时间内,只可以有一方发送或接收数据。
  • 全双工:同时可进行双向数据传输。

1、websocket 介绍

WebSocket 是 HTML5 下一种新的协议(WebSocket 协议本质上是一个基于 tcp 的协议),WebSocket 协议在 2008 年诞生,2011 年成为国际标准。所有浏览器都已经支持了。

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,位于 OSI 模型的应用层。

WebSocket 的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息。

1.1、出现背景

HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。

这种通信模型有一个弊端:HTTP 协议无法实现服务器主动向客户端发起消息。很多网站为了实现推送技术,所用的技术都是轮询。即在特定得时间间隔,由浏览器对服务器发出 http 请求。

轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。因此,工程师们一直在思考,有没有更好的方法。WebSocket 就是这样发明的。

1.2、WebSocket 握手过程

  1. 浏览器、服务器建立 TCP 连接,三次握手。这是通信的基础,若失败后续都不执行。
  2. TCP 连接成功后,浏览器通过 HTTP 协议向服务器传送 WebSocket 支持的版本号等信息。(开始前的 HTTP 握手)
  3. 服务器收到客户端的握手请求后,同样采用 HTTP 协议回馈数据。
  4. 当收到了连接成功的消息后,通过 TCP 通道进行传输通信。

一旦 WebSocket 连接建立后,后续数据都以帧序列的形式传输。在客户端断开WebSocket 连接或 Server 端中断连接前,不需要客户端和服务端重新发起连接请求。在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实现了“真·长链接”,实时性优势明显。

1.3、WebSocket 的特点

  1. 建立在 TCP 协议之上,服务器端的实现比较容易。
  2. 与 HTTP 协议有着良好的兼容性。默认端口也是 80 和 443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
  3. 数据格式比较轻量,性能开销小,通信高效。
  4. 可以发送文本,也可以发送二进制数据。
  5. 没有同源限制,客户端可以与任意服务器通信。
  6. 协议标识符是 ws(如果加密,则为 wss),服务器网址就是 URL。例如 ws://example.com:80/some/path
  7. 是真正的全双工方式,建立连接后客户端与服务器端是完全平等的,可以互相主动请求。而 HTTP 长连接基于 HTTP,是传统的客户端对服务器发起请求的模式。
  8. HTTP 长连接中,每次数据交换除了真正的数据部分外,服务器和客户端还要大量交换 HTTP header,信息交换效率很低。WebSocket 协议通过第一个 request 建立了 TCP 连接之后,之后交换的数据都不需要发送 HTTP header 就能交换数据,这显然和原有的 HTTP 协议有区别,所以它需要对服务器和客户端都进行升级才能实现(主流浏览器都已支持 HTML5)

1.4、WebSocket 与 HTTP 比较

HTTP 不同版本简介

  • 相同点

    • 都是一样基于 TCP 的,都是可靠性传输协议。
    • 都是应用层协议。
  • 不同点

    • WebSocket 是持久连接,HTTP 是短连接;
    • WebSocket 的协议是以 ws/wss 开头,HTTP 对应的是 http/https;
    • WebSocket 是有状态的,HTTP 是无状态的;
    • WebSocket 连接之后服务器和客户端可以双向发送数据,HTTP 只能是客户端发起一次请求之后,服务器才能返回数据;
    • WebSocket 连接建立之后,不需要再发送 request 请求,数据直接从 TCP 通道传输。
  • 联系

    • WebSocket 在建立握手时,数据是采用 HTTP 协议传输的。

2、HTTP 协议头

请求

  • Accept: text/html,application/xhtml+xml,application/xml
  • Accept-Encoding: gzip, deflate, br
  • Accept-Language: zh-CN,zh;q=0.9
  • Connection: keep-alive
  • Host: www.baidu.com
  • User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36

响应

  • Connection: keep-alive
  • Content-Encoding: gzip
  • Content-Type: text/html;charset=utf-8
  • Date: Sat, 16 Apr 2022 10:43:46 GMT
  • Server: BWS/1.1

3、WebSocket 协议头

请求

  • Accept-Encoding: gzip, deflate
  • Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
  • Connection: Upgrade
  • Host: 192.168.1.2:8080
  • Sec-WebSocket-Key: 821VqJT7EjnceB8m7mbwWA==
    • 是一个 Base64 encode 的值,这个是浏览器随机生成的
  • Sec-WebSocket-Version: 13
    • WebSocket 协议版本
  • Upgrade: WebSocket
    • 向服务器指定协议类型,告诉 web 服务器当前使用的是 WebSocket 协议
  • User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36 Edg/100.0.1185.39

响应

  • Connection: Upgrade
  • Date: Sat, 16 Apr 2022 10:49:05 GMT
  • Sec-WebSocket-Accept: paFykwJusIMnfpohWxA5HVpjD1Q=
    • 是经过服务器确认,并且加密过后的 Sec-WebSocket-Key。用来证明客户端和服务器之间能进行通信了。
  • Server: Server
  • Upgrade: websocket

4、WebSocket 连接创建过程

WebSocket 并不是全新的协议,而是利用了 HTTP 协议来建立连接。我们来看看 WebSocket 连接是如何创建的。

首先,WebSocket 连接必须由浏览器发起,因为请求协议是一个标准的 HTTP 请求,格式如下:

1
2
3
4
5
6
7
GET ws://localhost:3000/ws/chat HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Origin: http://localhost:3000
Sec-WebSocket-Key: client-random-string
Sec-WebSocket-Version: 13

该请求和普通的 HTTP 请求有几点不同:

  1. GET 请求的地址不是类似 /path/,而是以 ws:// 开头的地址;
  2. 请求头 Upgrade: websocketConnection: Upgrade 表示这个连接将要被转换为 WebSocket 连接;
  3. Sec-WebSocket-Key 是用于标识这个连接,并非用于加密数据;
  4. Sec-WebSocket-Version 指定了 WebSocket 的协议版本。

随后,服务器如果接受该请求,就会返回如下响应:

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

该响应代码 101 表示本次连接的 HTTP 协议即将被更改,更改后的协议就是 Upgrade: websocket 指定的 WebSocket 协议。

版本号和子协议规定了双方能理解的数据格式,以及是否支持压缩等等。如果仅使用 WebSocket 的 API,就不需要关心这些。

现在,一个 WebSocket 连接就建立成功,浏览器和服务器就可以随时主动发送消息给对方。消息有两种,一种是文本,一种是二进制数据。通常,我们可以发送 JSON 格式的文本,这样,在浏览器处理起来就十分容易。

为什么 WebSocket 连接可以实现全双工通信而HTTP连接不行呢?

实际上 HTTP 协议是建立在 TCP 协议之上的,TCP 协议本身就实现了全双工通信,但是 HTTP 协议的请求-应答机制限制了全双工通信。WebSocket 连接建立以后,其实只是简单规定了一下:接下来,咱们通信就不使用 HTTP 协议了,直接互相发数据吧。

安全的 WebSocket 连接机制和 HTTPS 类似。首先,浏览器用 wss://xxx 创建 WebSocket 连接时,会先通过 HTTPS 创建安全的连接,然后,该 HTTPS 连接升级为 WebSocket 连接,底层通信走的仍然是安全的 SSL/TLS 协议。


WebSocket 简介
https://flepeng.github.io/021-frontend-WebSocket-简介/
作者
Lepeng
发布于
2021年7月5日
许可协议