
1. WebSocket简介WebSocket 是一种全双工通信协议允许客户端和服务器之间建立持久化的双向通信连接。WebSocket 协议设计的初衷是解决 HTTP 协议在实时交互上的局限性例如长轮询、Ajax 等方法的高延迟问题。WebSocket 可以在单个 TCP 连接上实现客户端与服务器之间的实时、低延迟的数据传输。1.1 单工、半双工和双工这三个术语用于描述通信的方向性主要适用于数据传输和网络通信。它们的定义如下单工Simplex单工通信是单向的数据只能从发送方传送到接收方而无法反向传输通信过程不支持回复或反馈。电视广播信号从发射台发送到电视但观众无法向发射台发送信号。传统的广播电台信号从发射台发送到收音机但听众无法向发射台发送信号。半双工Half-Duplex半双工通信是双向的但在任意时刻只能有一个方向的数据传输。发送方和接收方可以交替发送和接收数据但不能同时进行。对讲机一个人说话时另一方需要等待直到说话者结束才能回复。双工Full-Duplex双工通信是完全双向的数据可以同时在两个方向传输。发送方和接收方可以同时发送和接收数据。电话通话两人可以同时讲话和听到对方的声音。网络通信如以太网。因此关于单工、半双工、双工通信的方向性我们可以做如下总结单工单向通信无法反馈。半双工双向通信但不能同时进行。双工双向通信可以同时进行。所以我们可以根据不同的应用场景选择合适的通信方式来提高数据传输的效率和用户体验。1.2 Http的局限性HTTP超文本传输协议是一种用于传输数据的协议但它也有一些局限性主要包括以下几点1.无状态性HTTP 是一种无状态协议每个请求都是独立的不会保留客户端的上下文信息。这使得实现用户会话和状态管理变得复杂需要额外的机制如 cookies 或 sessions。2.性能问题延迟每次请求都需要重新建立连接尤其是在使用 HTTP/1.1 时存在多个请求时会造成额外的延迟。带宽浪费每次请求都需要发送请求头增加了网络带宽的消耗。3.安全性加密不足传统的 HTTP 传输是明文的数据在传输过程中容易被窃听和篡改。虽然可以通过 HTTPSHTTP Secure来增强安全性但 HTTP 本身并不提供加密。4.不支持双向通信HTTP 是请求-响应模型客户端发起请求后服务器才能响应不支持实时双向通信。这在需要即时数据传输的应用中如聊天应用造成了限制。5.请求重定向和缓存管理的复杂性在复杂的应用中HTTP 请求的重定向和缓存管理可能导致性能下降和数据一致性问题增加了开发和维护的复杂性。6.适应性差HTTP 的设计初衷是用于静态网页的传输对于现代动态内容和实时应用如流媒体、在线游戏等支持不够灵活。虽然 HTTP 是互联网通信的基础但其局限性促使开发者寻求更高效、更安全的替代方案如 WebSocket、HTTP/2 和 HTTP/3 等。理解这些局限性有助于在设计系统时做出更明智的选择。2. WebSocket 协议2.1 协议标准WebSocket 是基于 TCP 的协议定义在 IETF 的 RFC 6455 标准中后由 RFC 7936 补充规范。。WebSocket 的连接从一个标准的 HTTP 请求开始经过一次协议升级后建立起一个全双工的 WebSocket 连接。WebSocket 默认使用以下两个端口80 端口非加密的 WebSocket 协议使用 ws:// 开头的 URL。443 端口加密的 WebSocket 协议通过 TLS/SSL 加密使用 wss:// 开头的 URL。WebSocket 的 URL 格式与 HTTP 类似但有一些特定的细节。以下是 WebSocket URL 的基本结构ws://[host]:[port]/[path]可以看到 WebSocket 的 URL 一共由四部分构成下面是关于它们的具体说明1.协议ws://表示 WebSocket 协议。wss://表示 WebSocket Secure加密的 WebSocket类似于 HTTPS。2.主机host服务器的域名或 IP 地址例如 example.com 或 192.168.1.100。3.端口port可选WebSocket 默认端口是 80ws和 443wss可以省略。如果使用其他端口则需要显式指定例如 :8080。4.路径path服务器上用于 WebSocket 连接的具体路径例如 /socket。下面是几个关于 WebSocket URL 格式的几个示例1.非加密的 WebSocket 连接ws://example.com/socket2.加密的 WebSocket 连接wss://example.com/socket3.指定端口的连接ws://example.com:8080/socket4.带路径的连接wss://example.com/api/v1/chatWebSocket URL 的格式与 HTTP URL 类似主要区别在于使用的协议前缀ws 或 wss。使用时要确保服务器能够处理 WebSocket 连接并在前端正确配置 URL。2.2 工作原理2.2.1 握手阶段WebSocket 连接从 HTTP 请求开始客户端通过 HTTP 升级机制请求升级协议1.客户端发起 HTTP 请求并在请求头中包含特定的 WebSocket 字段以表示希望建立 WebSocket 连接。示例Http请求消息部分GET /chat HTTP/1.1 Host: example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ Sec-WebSocket-Version: 13关键字段说明Upgrade: websocket表示希望将协议升级为 WebSocket。Connection: Upgrade告知服务器此次连接希望协议升级。Sec-WebSocket-Key客户端生成的随机密钥用于服务器生成握手应答的 Sec- WebSocket-Accept。Sec-WebSocket-Version指定 WebSocket 的版本当前标准版本是 13。2.服务器收到请求后返回 101 状态码并附带确认的握手信息。示例 http响应消息部分HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbKxOo关键字段说明HTTP/1.1 101 Switching Protocols 状态行它由三个部分组成1.协议版本HTTP/1.1 表示使用的 HTTP 版本。2.状态码101 是状态码表示服务器已接受客户端的请求并正在切换协议。3.状态描述Switching Protocols 是对状态码的描述说明了服务器的响应内容。Sec-WebSocket-Accept由 Sec-WebSocket-Key 和特定算法生成的哈希值用于确认握手的安全性。2.2.2 数据帧传输WebSocket 的数据通过帧 (frame) 进行传输帧是指在客户端和服务器之间传输的数据单元。每一帧都有固定的格式包含数据以及控制信息。WebSocket 支持以下几种帧类型文本帧Text Frame用于传输文本数据通常是 UTF-8 编码的字符串。二进制帧Binary Frame用于传输二进制数据如图片、音视频数据等。关闭帧Close Frame用于关闭连接。Ping 和 Pong 帧用于检测连接的活跃性Ping 由客户端或服务器发送Pong 由对方响应。每个 WebSocket 数据帧的格式如下0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -------------------------------------------------------- |F|R|R|R| opcode|M| Payload len | Extended payload length | |I|S|S|S| (4) |A| (7) | (16/64) | |N|V|V|V| |S| | (if payload len126/127) | | |1|2|3| |K| | | ------------------------- - - - - - - - - - - - - - - - | Extended payload length continued, if payload len 127 | - - - - - - - - - - - - - - - ------------------------------- | |Masking-key, if MASK set to 1 | -------------------------------------------------------------- | Masking-key (continued) | Payload Data | -------------------------------- - - - - - - - - - - - - - - - : Payload Data continued ... : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | Payload Data continued ... | ---------------------------------------------------------------FIN: 1bit表示是否为最后一帧。如果为1表示这是最后一帧如果为0表示后面还有帧。RSV1, RSV2, RSV3各1bit保留位用于扩展协议。通常在初始实现中这些位应设置为0。Opcode: 4bit用于表示帧的类型。0x0继续帧0x1文本帧0x2二进制帧0x3~0x7预留给以后的非控制帧0x8连接关闭帧0x9Ping 帧0xAPong 帧0xB~0xF预留给以后的控制帧Mask: 1bit表示是否对数据进行掩码处理。客户端到服务器的消息必须使用掩码服务器到客户端的消息不需要使用掩码Payload length: 7bit/716bit/764bit表示数据的长度。当它的值在 0 到 125 之间时表示有效负载的字节数。当它的值是 1260x7E时表示后面将有 2 字节16 位来表示有效负载的真实长度有效负载长度在 0 到 65535 之间。当它的值是 1270x7F时则表示后面会有 8 字节64 位来表示有效负载的真实长度。Masking Key0或4bytes所有从客户端发往服务端的数据帧都已经与一个包含在这一帧中的32 bit的掩码进行了运算。如果mask标志位1 bit为1那么这个字段存在如果标志位为0那么这个字段不存在。Payload data实际传输的数据根据Payload length字段的值来确定长度。2.2.3 保持连接与心跳WebSocket 在建立连接后会保持连接状态直到一方显式关闭连接。为了防止连接由于网络问题或闲置超时而断开WebSocket 支持通过 Ping-Pong 机制 来检测连接的活跃性。客户端或服务器可以发送一个 Ping 帧接收方必须在合理时间内响应一个 Pong 帧确保连接仍然正常。Ping-Pong 机制的示例流程:1.客户端发送 Ping 帧:客户端发送一个 Ping 帧Payload Data 可能包含当前时间戳。帧格式| FIN | RSV | Opcode: 0x9 | MASK1 | Payload Length | Masking key6 | Payload Data时间戳 |2.服务器接收并响应 Pong 帧:服务器接收到 Ping 帧后立即发送一个 Pong 帧Payload Data 与接收到的 Ping 帧的 Payload Data 相同。帧格式| FIN | RSV | Opcode: 0xA | MASK0 | Payload Length | Payload Data时间戳 |3.客户端接收 Pong 帧:客户端接收到 Pong 帧后可以确认连接仍然活跃。客户端可以根据时间戳计算往返时间RTT以评估网络延迟。在使用 WebSocket 协议的 Ping-Pong 机制的时候有以下事项需要再次强调1.双向检测:客户端和服务器都可以发送 Ping 帧并期望对方发送 Pong 帧。这使得双方都能检测到连接的活跃性。2.超时处理:如果发送 Ping 帧的一方在一定时间内没有收到 Pong 帧可以认为连接已经断开或不活跃并采取相应的措施如关闭连接或重新连接。3.Payload Data:Ping 和 Pong 帧的 Payload Data 是可选的但通常会包含一些简单的数据如时间戳以便双方能够进行更详细的检测和分析。2.2.4 关闭连接WebSocket 连接关闭时双方需要发送一个关闭帧Close Frame。关闭帧包含一个关闭码和关闭原因可以用于表明连接关闭的原因。具体来说关闭帧的格式遵循 WebSocket 协议规范其中状态码的位置和结构如下1.FIN 位: 1 bit2.RSV 位: 3 bits (保留位一般用于扩展)3.Opcode: 4 bits (对于关闭帧值为 0x8)4.MASK: 1 bit (指示消息是否被掩码客户端消息必须掩码)5.Payload length: 7 bits, 716 bits, 或 764 bits (指示随后的有效负载的长度)6.Masking key: 0或4 bytes (如果 MASK 位为 1则使用包含用于掩码的密钥)7.Payload data: (长度通过 Payload length 指定)关闭状态码: 在关闭帧的有效负载部分的最开始紧接在 Payload length 字段后面。这两个字节 未经掩码处理表示状态码Close Code。关闭原因: 状态码之后可以跟随一个可选的 UTF-8 字符串描述关闭的原因。常见的标准关闭码有1000正常关闭。1001服务器或客户端因特殊原因需要关闭如服务器关闭。1002协议错误。1003接收到不支持的数据类型。1006异常关闭没有收到关闭帧。1007收到包含不一致数据的帧导致连接关闭。例如格式不正确的内容。1009发送的消息超过了可以接收的大小。1011服务器遇到错误无法完成请求。1015当 WebSocket 连接在 TLS/SSL 握手期间失败时使用此状态码。除了上述标准状态码外使用者也可以定义自定义的关闭状态码通常建议使用在 1,000 到 1,999 之间的代码一定要注意避免与标准代码冲突。示例关闭帧字节流关闭流程非常简单就是发送和接收数据所以对于应用层的 WebSocket 而言就只有两步发送: 当一方要关闭连接时它会构造关闭帧并在 Payload 中写入状态码和可能的关闭原因然后将其发送给另一方。接收: 接收方在接收到关闭帧后会读取 Payload首先获取状态码然后读取可选的关闭原因从而知道连接关闭的具体情况。如果是基于 TCP 的四次挥手进行描述就是以下四步1.发起关闭请求:一方调用关闭操作连接的一方可以是客户端或服务器决定关闭连接时调用相应的 close() 方法。发送关闭帧主动断开连接的一方会创建并发送一个关闭帧Close Frame该帧包含关闭状态码和可选的关闭原因。2.接收关闭帧:接收帧被动断开连接的一方接收方收到关闭帧时会首先解析该帧的状态码和可选原因。处理关闭帧接收方可以根据关闭状态码进行相应的处理例如记录日志更新连接状态等。3.发送响应的关闭帧 (Pong):回应关闭请求接收方在确认关闭请求后可能进行清理操作会发送自己的关闭帧这通常是一个回应帧。格式该响应关闭帧也会包含一个状态码通常是 1000正常关闭并可能附带关闭原因。4.最终关闭连接:双方完成关闭一旦双方都发送并接收了关闭帧WebSocket 连接将被正式关闭。清理资源关闭连接时双方可以释放相关资源如定时器、事件监听器等。2.2.5 安全性WebSocket 使用 wssWebSocket Secure协议进行安全通信的方式与使用 wsWebSocket协议类似但需要额外的安全配置。WSS: 是通过 TLS/SSL 加密的 WebSocket 协议类似于 HTTPS 相对于 HTTP 的形式。使用 WSS 可以确保数据在传输过程中得到加密避免被窃听和篡改。端口: WSS 通常使用 443 端口而 WS不安全使用 80 端口。在使用 WSS 时必须提供有效的 SSL/TLS 证书。可以使用自签名证书: 用于开发和测试但浏览器可能会显示安全警告。公认的证书: 从受信任的证书颁发机构获取的证书用于生产环境以确保通信的安全性。3. webSocket和Http对比3.1 相同点和不同点相同点1.应用层协议WebSocket 和 HTTP 都属于应用层协议主要用于数据的传输。2.基于 TCP两者都依赖于 TCP 协议进行底层的数据传输确保数据的可靠性和顺序。3.跨平台兼容性WebSocket 和 HTTP 都可以在不同的平台和设备上使用支持跨浏览器和跨设备的通信。4.使用标准的 URLWebSocket 和 HTTP 都使用类似的 URL 结构例如 http:// 和 ws://。不同点1.连接模式HTTP每次请求都是独立的需要重新建立连接适合于一次性请求的场景。WebSocket连接建立后可以保持很长时间适合需要频繁数据交换的场景。2.通信方式HTTP客户端发起请求服务器响应适用于请求-响应模式。WebSocket客户端和服务器可以随时发送消息适合双向通信。3.延迟HTTP每次请求都需要经过建立和关闭连接的过程导致较高的延迟。WebSocket连接建立后数据传输几乎是即时的延迟较低。4.数据格式HTTP通常以文本格式传输如 JSON、HTML 等。WebSocket支持更灵活的数据格式包括二进制数据适合多种应用场景。5.状态保持HTTP每个请求都是独立的无状态设计。WebSocket连接是持久的可以保持状态适合需要长时间交互的应用。6.心跳机制HTTP没有内置机制检测连接的存活状态。WebSocket通过 Ping/Pong 帧来保持连接活跃性检测连接状态。WebSocket 和 HTTP 各自有其适用的场景和优势。HTTP 适合传统的请求-响应模式而 WebSocket 则更适合需要实时、双向交互的应用。在现代 Web 开发中根据应用的需求选择合适的协议可以大大提高性能和用户体验。3.2 应用场景HTTP 的应用场景1.静态网页加载用于加载 HTML、CSS、JavaScript 文件等静态资源。2.RESTful API适合请求-响应模型常用于获取、创建、更新和删除数据。3.文件下载和上传支持大文件的上传和下载适合需要处理文件的场景。4.搜索引擎用于搜索查询返回结果数据。5.内容管理系统用于管理和发布网站内容支持用户交互。WebSocket 的应用场景1.实时聊天应用支持用户之间的即时消息传递如聊天工具和社交平台。2.在线游戏实时数据传输确保游戏状态和玩家动作的即时更新。3.金融交易平台实时更新股票价格、交易信息和市场动态适合高频交易。4.实时协作工具适合文档编辑、白板协作等场景支持多人实时互动。5.物联网IoT应用设备之间的实时数据交换和监控适合智能家居和工业应用。6.推送通知实时推送消息如新闻更新、社交媒体通知等。因此我们就可以得到以下结论:HTTP 更适合于请求-响应式的交互适用于大多数常规的数据传输需求。WebSocket 则专为实时、双向的通信而设计适合需要快速响应和持续连接的应用场景。选择合适的协议可以根据具体的应用需求和用户体验进行优化。附录RESTful通常被称为 RESTRepresentational State Transfer是一种软件架构风格用于设计网络应用程序。它基于HTTP协议并遵循一组设计原则和约束以实现可伸缩的、灵活的网络服务。REST 的设计理念是1.资源 - 网络上的每个实体都是一个资源。资源可以是一个文档、一个人、一个事件等。2.表现形式Representations - 资源的某个具体状态可以通过不同的表现形式来表示。例如一个人的资源可以通过文本、图片或其他任何形式来表示。3.状态转移State Transfer - 客户端通过发送请求到服务端请求可能会改变服务端的状态例如创建新的资源更新资源状态读取资源状态等。RESTful 应用程序的典型特征包括使用 HTTP方法如GET、POST、PUT、DELETE来操作数据。通过 URL统一资源定位符来表示资源的地址。使用 标准数据格式如JSON或XML来描述资源的表现形式。分离 客户端和服务器端状态以便每个请求可以独立完成操作。无状态的设计每次请求都包含必要的信息不依赖于之前的请求这有助于实现高可伸缩性。超媒体作为自描述的指南在响应中包含链接以此作为导航的指南。RESTful 设计原则通常用于创建现代网络上通信的 Web 服务和 API。由于其无状态性和分层架构RESTful API 适合处理高并发请求并且可以通过缓存和代理来改善性能和扩展性。笔记http协议的使用场景是在进行网络通信的时候并且客户端是浏览器如果客户端是浏览器那么约定俗成使用http或者https协议http请求是由客户端发起的get请求静态资源post请求动态资源语义与设计初衷从 HTTP 协议的设计标准来看GET 和 POST 的定位很明确GET 用于从服务器获取资源是“只读”的而 POST 用于向服务器提交数据通常会导致状态的改变。这个区别引出了两个在设计上很重要的特性幂等性 (Idempotence)这是指多次执行同一个请求对服务器资源产生的效果是相同的。标准认为GET 请求应该是幂等的因为它只获取数据而 POST 请求不是幂等的因为多次提交可能会创建多条记录。安全性 (Safe)一个“安全”的方法意味着它不会修改服务器数据。GET 就被定义为安全的这也是浏览器可以对 GET 请求进行缓存、书签收藏等操作的前提。语义不同GET 是“查”POST 是“改”。数据位置不同GET 参数在 URL 里POST 数据在 Body 里。特性不同GET 可以被浏览器缓存、收藏且是幂等的POST 则不推荐这样使用。常见误区POST 不会比 GET 更安全数据大小的限制也与协议本身无关。