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 握手过程
- 浏览器、服务器建立 TCP 连接,三次握手。这是通信的基础,若失败后续都不执行。
- TCP 连接成功后,浏览器通过 HTTP 协议向服务器传送 WebSocket 支持的版本号等信息。(开始前的 HTTP 握手)
- 服务器收到客户端的握手请求后,同样采用 HTTP 协议回馈数据。
- 当收到了连接成功的消息后,通过 TCP 通道进行传输通信。
一旦 WebSocket 连接建立后,后续数据都以帧序列的形式传输。在客户端断开WebSocket 连接或 Server 端中断连接前,不需要客户端和服务端重新发起连接请求。在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实现了“真·长链接”,实时性优势明显。
1.3、WebSocket 的特点
- 建立在 TCP 协议之上,服务器端的实现比较容易。
- 与 HTTP 协议有着良好的兼容性。默认端口也是 80 和 443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
- 数据格式比较轻量,性能开销小,通信高效。
- 可以发送文本,也可以发送二进制数据。
- 没有同源限制,客户端可以与任意服务器通信。
- 协议标识符是 ws(如果加密,则为 wss),服务器网址就是 URL。例如
ws://example.com:80/some/path
- 是真正的全双工方式,建立连接后客户端与服务器端是完全平等的,可以互相主动请求。而 HTTP 长连接基于 HTTP,是传统的客户端对服务器发起请求的模式。
- HTTP 长连接中,每次数据交换除了真正的数据部分外,服务器和客户端还要大量交换 HTTP header,信息交换效率很低。WebSocket 协议通过第一个 request 建立了 TCP 连接之后,之后交换的数据都不需要发送 HTTP header 就能交换数据,这显然和原有的 HTTP 协议有区别,所以它需要对服务器和客户端都进行升级才能实现(主流浏览器都已支持 HTML5)
1.4、WebSocket 与 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 |
|
该请求和普通的 HTTP 请求有几点不同:
- GET 请求的地址不是类似
/path/
,而是以ws://
开头的地址; - 请求头
Upgrade: websocket
和Connection: Upgrade
表示这个连接将要被转换为 WebSocket 连接; Sec-WebSocket-Key
是用于标识这个连接,并非用于加密数据;Sec-WebSocket-Version
指定了 WebSocket 的协议版本。
随后,服务器如果接受该请求,就会返回如下响应:
1 |
|
该响应代码 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 协议。