为什么要有WebSocket?

TCP是全双工的,但HTTP是半双工的。在一些实时通信的场景中,HTTP需要通过频繁轮询或者长轮询来从服务器获取最新的信息,例如实时聊天应用、在线游戏、实时协作的场景。WeBSocket同样是基于TCP的协议,但它提供了全双工的通信能力,允许服务端主动推送数据给客户端。这也是有了HTTP,为什么还要有WebSocket的原因。

有了WebSocket为什么还要使用HTTP呢?

  • HTTP协议是一种成熟的、广泛应用的协议。适用于大多数非实时的请求-响应场景。
  • WebSocket适合长连接和实时通信,但是一次性请求-响应场景,HTTP更加简单高效。
  • HTTP无状态,WebSocket有状态,需要维护连接。
  • 并非所有客户端和服务器都支持WebSocket,有的受限的网络环境也不支持WebSocket。
  • RESTful API等多种标准都是基于HTTP的。

工作原理

WebScoket需要通过TCP建立连接,然后通过HTTP协议握手,握手成功之后,客户端和服务器建立持久连接,双方可以随时发送数据“帧”,支持文本和二进制数据。

握手

当客户端需要启用WebSocket时,会发送携带特殊头部字段的HTTP请求到服务端。例如:

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

其中:

  • Connection:Upgrade:当前连接支持协议升级。
  • Upgrade:websocket:希望从HTTP升级为WebSocket。
  • Sec-WebSocket-Key:随机生成的Base64字符串,用于验证握手请求。
  • Sec-WebSocket-Version:支持的版本号。

服务端收到请求后,用公开算法把Sec-WebSocket-Key转成另外的字符串,然后返回HTTP101的响应。例如:

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

客户端验证返回的Sec-WebSocket-Accept之后,握手完成,正式升级,后续通过WebSocket数据帧通信。

数据传输

WebSocket里面传输的数据包叫做数据帧。其中有一个比较重要的字段opcode,表示帧的类型,例如:

  • 0x1:文本帧(Text Frame)。
  • 0x2:二进制帧(Binary Frame)。
  • 0x8:关闭连接帧(Close Frame)。
  • 0x9:Ping 帧。
  • 0xA:Pong 帧。

关闭连接

需要关闭连接的一方直接发送一个关闭连接帧,另外一方也会发送关闭帧作为响应。这也叫做关闭握手,此后连接正式关闭,双方关闭底层的TCP连接,释放相关的资源。