HTTP 协议的通信只能由客户端发起。在一些场景下,这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用轮询:每隔一段时间,就发出一个询问,了解服务器有没有新的信息。
轮询的效率低,非常浪费资源。

这里简单介绍一些 ajax轮询和长轮询

ajax轮询

原理:让浏览器隔几秒就发送一次请求,询问服务器是否有新信息。
场景:来自知乎
客户端:啦啦啦,有没有新信息(Request)
服务端:没有(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:没有。。(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:你好烦啊,没有啊。。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:好啦好啦,有啦给你。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:。。。。。没。。。。没。。。没有(Response) —— loop
缺点:需要服务器有很快的处理速度和资源。(速度)

长轮询

原理:跟 ajax轮询 差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回 Response 给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
场景:来自知乎
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)
服务端:额。。 等待到有消息的时候。。来 给你(Response)
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request) -loop
缺点:需要有很高的并发,也就是说同时接待客户的能力。(场地大小)

WebSocket协议

WebSocket 是由 Web 浏览器和服务器之间的一种全双工通信协议。一旦 Web 服务器与客户端之间建立起 WebSocket 协议的通信连接,之后所有的通信都依靠这个专用协议进行。通信过程中可互相发送 JSON 、 XML 、 HTML 或图片等任意格式的数据。

WebSocket协议的主要特点:

  • 推送功能:支持由服务器向客户端推送数据的推送功能。这样,服务器可直接发送数据,而不必等待客户端的请求。
  • 减少通信量:只要建立起WebSocket连接,就希望一直保持连接状态。和HTTP相比,不但每次连接时的总开销减少,而且由于WebSocket的首部信息很小,通信量也相应减少了。

与HTTP协议的异同

相同点:

  • 都是基于 TCP 的应用层协议;
  • 都使用 Request/Response 模型进行连接的建立;
  • 在连接的建立过程中对错误的处理方式相同,在这个阶段 WebSocket 可能返回和 HTTP 相同的返回码;
  • 都可以在网络中传输数据。

不同点:

  • WS 使用 HTTP 来建立连接,但是定义了一系列新的 header 域,这些域在 HTTP 中并不会使用;
  • WS 的连接不能通过中间人来转发,它必须是一个直接连接;
  • WS 连接建立之后,通信双方都可以在任何时刻向另一方发送数据;
  • WS 连接建立之后,数据的传输使用帧来传递,不再需要 Request 消息;
  • WS 的数据帧有序。

通信过程

TCP 连接建立后,客户端发送 websocket 的握手请求,请求报文头部如下:

  1. GET /uin=xxxxxxxx&app=xxxxxxxxx&token=XXXXXXXXXXXX HTTP/1.1
  2. Host: server.example.cn:443
  3. Connection: Upgrade
  4. Pragma: no-cache
  5. Cache-Control: no-cache
  6. User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36
  7. Upgrade: websocket
  8. Sec-WebSocket-Version: 13
  9. Accept-Encoding: gzip, deflate
  10. Accept-Language: zh-CN,zh;q=0.9
  11. Cookie: user_id=XXXXX
  12. Sec-WebSocket-Key: 1/2hTi/+eNURiekpNI4k5Q==
  13. Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
  14. Sec-WebSocket-Protocol: binary, base64
  • 第一行为请求的方法,类型必须为 GET ,协议版本号必须大于 1.1
  • Upgrade 字段必须包含,值为 websocket
  • Connection 字段必须包含,值为 Upgrade
  • Sec-WebSocket-Key 字段必须包含,记录着握手过程中必不可少的键值。是一个 Base64 encode 的值,这个是浏览器随机生成的。
  • Sec-WebSocket-Protocol 字段必须包含,记录着使用的子协议。是一个用户定义的字符串,用来区分同 URL 下,不同的服务所需要的协议。
  • Origin:指明请求的来源。Origin 头部主要用于保护 WebSocket 服务器免受非授权的跨域脚本调用 WebSocket API 的请求。

响应:服务器接收到请求后,返回状态码为 101 Switching Protocols 的响应。

  1. HTTP/1.1 101 Switching Protocols
  2. Server: WebSockify Python/2.6.6
  3. Date: Wed, 27 May 2020 03:03:21 GMT
  4. Upgrade: websocket
  5. Connection: Upgrade
  6. Sec-WebSocket-Accept: hXXXXXXXXXXXXXXxGmM=
  7. Sec-WebSocket-Protocol: binary
  • Sec-WebSocket-Accept 表示经过服务器确认,并且对客户端的 Sec-WebSocket-Key 进行了加密
  • Sec-WebSocket-Protocol:表示最终使用的协议

image.png

参考文章