Part1WebSocket是什么
WebSocket是一种网络传输协议,可以在单个TCP连接上进行全双工通信,它位于OSI模型的应用层。
WebSocket与HTTP不是同一种协议,虽然两者都位于OSI模型的应用层,并且都依赖底层的TCP协议。它们有着各自的协议格式,应用不同的场景。WebSocket协议本身不依赖于HTTP协议,但是在WebSocket最初的建立阶段依赖于HTTP,因为在WebSocket的握手过程使用了HTTP请求来升级协议。
WebSocket协议URL与HTTP类似,明文协议scheme为ws:,对应到HTTP协议是http:。基于SSL/TLS的WebSocket协议的scheme为wss:, 对应到HTTP协议是https:。ws默认端口为80,wss默认端口为443。
Part2为什么需要WebSocket
web通信已经有了HTTP协议,为啥还要搞一个WebSocket协议呢?一定是HTTP协议不能满足某些场景下的需求。下面先分析HTTP协议存在问题,然后分析WebSocket是如何工作的。
1HTTP协议
HTTP是请求应答通信模型,即客户端主动向服务器发送Request请求,服务器回复Response数据。服务器无法主动地向客户端发送资源,所以HTTP协议下客户端和服务器之间是非对称工作方式,是一种半双工通信。
当客户端向服务器发送一个HTTP请求时,客户端和服务器之间打开一个TCP连接,并且在接收到响应后,这个TCP连接会被终止。每个HTTP请求都会向服务器打开一个单独的TCP连接,如果客户端向服务器发送了10个请求,就会打开10个独立的TCP连接。
HTTP协议存在如下问题:
- 实时性差:通过前面HTTP协议介绍可以看到,HTTP采用的是请求应答模型,服务器无法主动向客户端发送消息。无法满足一些应用场景需求,像在线游戏、实时数据更新。如果采用HTTP协议实现,需要通过轮询来实现,及时性很差。
- 性能不高:每次请求都会打开TCP连接,请求应答后连接关闭,在频繁通信的场景下,这种频繁TCP建立连接和关闭连接,很消耗性能。
所以引入WebSocket协议解决HTTP存在的问题。
2WebSocket协议
WebSocket协议交互过程如下图,整个过程分为两个阶段。阶段1:进行握手。阶段2:进行数据传输。
握手
出于兼容性考量,握手采用HTTP来实现。客户端发送的握手消息是一个带有Upgrade头的HTTP Request消息。具体长下面这样。
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
- 通过GET发送HTTP请求,需要HTTP版本号>=1.1
- Host:主机名,用于客户端和服务端都能验证它们是否使用的是同一个主机
- Upgrade: 升级到WebSocket协议
- Connection:连接类型应该被升级,通常与Upgrade一起使用
- Sec-WebSocket-Key:随机生成的16字节内容,然后通过Base64编码。确保服务端能够正确地响应客户端的请求,从而验证服务端的身份
- Sec-WebSocket-Protocol:指定使用哪个协议
- Sec-WebSocket-Version:客户端可以接受哪些子协议
服务端回复给客户端的报文如下。
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
- 101: 服务端响应101状态码,任何非101状态码都会导致错误,意味着WebSocket握手未完成
- Sec-WebSocket-Accept:将客户端传过来的Sec-WebSocket-Key 和全局唯一标识符组合后的Base64编码哈希值。
如果Sec-WebSocket-Accept的值与预期值不匹配,缺少头字段或者HTTP状态码不是101,那么连接将不会被建立,也不会发送数据帧。
发送数据
WebSocket数据帧格式如下:
- FIN:占1个bit,标记这个帧是不是消息中的最后一个帧,第一个帧也可以是最后一个帧。因为在WebSocket通信中,一个完整的消息可能需要分成多个帧来传输,而FIN字段就用来告诉对方是否还有后续的帧。
- RSV1/RSV2/RSV3:各占1个bit,值必须是0。
- opcode:操作码,占4个bit, 表示数据载荷 payload data类型,详情见下表。
- MASK:掩码标识,占1个bit。表示载荷数据 payload data是否被掩码。如果设置为1,Masking-key部分有一个掩码钥匙,用这个钥匙对载荷数据进行掩码操作。
- Payload len: 数据长度,占用7/(7+16)/(7+64)个bit位。如果值在0-125之间,则该值大小就表示数据长度。如果值为126,则接下来的两个字节(16bit)表示的16位无符号整数即为数据长度。如果值为127,则接下来八个字节(64bit)表示的64位无符号整数即为数据长度。
- Masking key:掩码钥匙,占用0或4个字节,所有客户端发送到服务端的数据必须使用一个32位值进行掩码。
- Payload data:应用数据。
操作码值 | 含义 |
0 | 继续帧 |
1 | 文本帧 |
2 | 二进制帧 |
3-7 | 保留 |
8 | 关闭帧 |
9 | ping帧 |
10 | pong帧 |
11-15 | 保留 |
Part3WebSocket使用场景
1实时Web应用程序
实时Web应用程序使用WebSocket连接来展示服务器发送的数据。例如,在交易网站或股票交易中,价格总是波动,向客户端展示价格时延迟要尽可能小。
2游戏应用程序
在游戏应用程序中,客户端持续向服务器发送数据,然后服务器在不刷新用户界面的情况下将数据发送回客户端。
3聊天应用程序
大多数聊天应用程序使用WebSocket提供用户之间不间断和快速的通信渠道。
4实时协作编辑
像各种云文档,例如腾讯文档、石墨文档等。
5实时数据可视化
前端可以通过WebSocket通道从后端获取数据,自动更新数据图表,如条形图、饼图等。在数据统计分析、数字化大屏领域用的很多。
6实时定位应用
移动应用中实时共享位置更新。
7语音识别应用
语音识别,实时返回识别后的文字。