WebSocket (1)

154 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情

今天做完一个任务在自测接口的时候,有另一部分数据的返回,没找到是调的哪个接口返回的,问了旁边更熟悉项目的大佬,说这些数据调的是 WebSocket 请求,然后在 F12 中的 WS 下看到了返回的数据,以前从来没在这里看过接口,趁此梳理一下 WebSocket......

image.png

Http 三次握手

首先,我想先提一下 Http 的三次握手,因为 WebSocket 跟 Http 比较类似。而且关于 Http 我前面也已经整理过,可以看这里(下图也来自这里)。这里我也再简单说一下三次握手:

image.png

  • 第一次握手: 客户端发送一个内容 SYN,和初始化序列号 seq。如果服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
  • 第二次握手: 服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且发送自己的 ACK 报文和初始化序列号 seq。同时会把客户端的 初始化序列号 seq + 1 作为相应确认收到 ack 的值,表示自己已经收到了客户端的 SYN。如果客户端收到了这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常;
  • 第三次握手: 客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 seq+ 1 作为 ack 的值,表示已经收到了服务端的 SYN 报文,服务器收到 ACK 报文之后双方已建立起了连接。

这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。所以需要三次握手才能确认双方的接收与发送能力是否正常。

WebSocket 连接过程

WebSocket 就像 Http 一样,则是一个典型的应用层协议。在 WebSocket中,只需要服务器和浏览器通过 Http 协议进行一个握手的动作,然后单独建立一条 TCP 的通信通道进行数据的传送。

  • 首先,客户端发起 Http 请求,经过3次握手后,建立起 TCP 连接;Http 请求里存放 WebSocket 支持的版本号等信息,如:Upgrade、Connection、WebSocket-Version 等;
  • 然后,服务器收到客户端的握手请求后,同样采用 Http 协议回馈数据;
  • 最后,客户端收到连接成功的消息后,开始借助于 TCP 传输信道进行全双工通信。WebSocket 协议下客服端和浏览器可以同时发送信息。

客户端开始建立 WebSocket 连接时要发送一个 header 标记了 Upgrade 的 Http 请求,表示请求协议升级。

WebSocket 请求&响应

客户端发送的数据格式

GET /webfin/websocket/ HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==
Origin: http://localhost:8080Sec-\ WebSocket-Version: 13

服务器回应的数据格式

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Location: ws://example.com/

字段说明

  • Connection 必须设置 Upgrade,表示客户端希望连接升级;
  • Upgrade 字段必须设置 WebSocket,表示希望升级到 WebSocket 协议。
  • Sec-WebSocket-Key 是随机的字符串,服务器端会用这些数据来构造出一个 SHA-1 的信息摘要。把 “Sec-WebSocket-Key” 加上一个特殊字符串 “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,然后计算 SHA-1 摘要,之后进行 BASE-64 编码,将结果作为 “Sec-WebSocket-Accept” 头的值,返回给客户端。如此操作,可以尽量避免普通 Http 请求被误认为 WebSocket 协议。
  • Sec-WebSocket-Version 表示支持的 WebSocket 版本。RFC6455 要求使用的版本是 13,之前草案的版本均应当弃用。
  • Origin 字段是可选的,通常用来表示在浏览器中发起此 WebSocket 连接所在的页面,类似于 Referer。但是,与 Referer 不同的是,Origin 只包含了协议和主机名称。
  • 其他一些定义在 Http 协议中的字段,如 Cookie 等,也可以在 WebSocket 中使用。

先简单梳理一下 WebSocket 连接的过程以及请求/响应的数据格式以及各字段大致代表什么含义,前面提到 WebSocket 和 Http 比较相似,下次再说二者具体有什么区别......
希望本文能够帮到你,如有错误,望指正!
我向你敬礼啊,Salute!