websocket

发布于:2025-05-27 ⋅ 阅读:(31) ⋅ 点赞:(0)

1、socket连接特点

(1) 面向连接的可靠传输

TCP 协议通过以下机制保证可靠性:

  • 三次握手建立连接:确保双方通信链路正常,避免 “假连接”。
  • 确认与重传机制:发送方会为每个数据包设置超时计时器,若未收到接收方的 ACK 确认,会重新发送数据包。
  • 流量控制与拥塞控制:通过滑动窗口机制避免接收方因处理能力不足导致数据丢失。
(2)字节流传输保证顺序性

Redis 主从复制需要严格保证命令执行顺序(如先执行 SET a 1,再执行 INCR a,结果必须是 2)。TCP 协议的 “字节流” 特性可以保证:

  • 发送方按顺序写入 Socket 的数据,接收方会按相同顺序读取。
  • 数据无边界(无消息头),但通过序列号(Sequence Number)和确认号(ACK Number)确保接收方正确拼接字节流。

相比之下,UDP(用户数据报协议)是无连接、不可靠、面向数据报的协议,无法保证顺序性和完整性,因此不适合主从复制场景。

(3)长连接支持持续命令同步

主从复制不仅需要初始的数据同步(全量或增量),还需要长期保持连接以同步后续的写命令(如主节点接收的 SETHSET 等操作)。TCP Socket 连接可以保持长时间的通信(除非主动断开或网络故障),而 UDP 每次通信都需要重新寻址,无法高效支持这种 “持续推送” 场景。

2、对其他通信协议的优势

可能有人会问:“为什么不用 HTTP、gRPC 等更上层的协议?” 原因在于:

  • HTTP 是短连接 + 请求响应模式:每次通信需要重新建立连接(HTTP/1.1 虽支持长连接,但默认是短连接),无法高效支持主节点主动向从节点 “推送” 命令的场景(主节点需要实时通知从节点新命令)。
  • gRPC 等 RPC 框架:虽然支持长连接和流式传输,但会引入额外的序列化 / 反序列化开销(如 Protobuf),而 Redis 的协议(RESP)本身是轻量的文本协议,直接通过 Socket 传输更高效。

3、websocket的原理

好的,面试官。我们来聊聊WebSocket的原理。

WebSocket是什么?

WebSocket是一种在单个TCP连接上进行全双工、双向通信的协议。它旨在解决HTTP协议在实现实时、双向通信方面的不足。

  • 全双工 (Full-Duplex):客户端和服务器可以同时独立地发送和接收数据,不需要像HTTP那样一来一回的请求-响应模式。

  • 双向通信 (Bi-directional):数据可以在客户端到服务器和服务器到客户端两个方向上自由流动。

  • 单个TCP连接:一旦WebSocket连接建立,所有的后续通信都在这一个TCP连接上进行,避免了HTTP协议中频繁建立和关闭TCP连接的开销。

为什么需要WebSocket?HTTP的局限性:

传统的HTTP协议是无状态的、单向的(客户端发起请求,服务器响应)。为了在Web上实现类似即时通讯、实时数据更新等功能,开发者们曾尝试过一些变通方法,但都有其局限性:

  1. 轮询 (Polling):客户端定期向服务器发送HTTP请求,询问是否有新数据。

    • 缺点:实时性差(取决于轮询间隔),大量无效请求浪费带宽和服务器资源。

  2. 长轮询 (Long Polling):客户端发送一个HTTP请求,服务器保持连接打开,直到有新数据才响应。响应后,客户端立即再次发起新的长轮询请求。

    • 缺点:仍然有连接建立和关闭的开销,服务器需要管理大量挂起的连接,对服务器资源消耗较大。

  3. SSE (Server-Sent Events):允许服务器单向地向客户端推送数据流。

    • 缺点:只能服务器向客户端单向推送,客户端无法通过同一连接向服务器发送数据(需要另外的HTTP请求)。

WebSocket的出现,就是为了在Web上提供一种更高效、更原生的双向实时通信解决方案。

WebSocket的工作原理(核心流程):

  1. 握手阶段 (Handshake) - 基于HTTP

    • 初始连接:WebSocket的连接过程始于一个标准的HTTP请求,但这个请求有一些特殊的头部信息,表明客户端希望将连接从HTTP升级(Upgrade)到WebSocket协议。

    • 客户端请求

      • 请求方法通常是 GET。

      • Upgrade: websocket 头部:表明希望升级到WebSocket协议。

      • Connection: Upgrade 头部:表明连接类型需要升级。

      • Sec-WebSocket-Key 头部:客户端生成一个随机的Base64编码的字符串,用于后续的安全校验。

      • Sec-WebSocket-Version 头部:指定了客户端期望使用的WebSocket协议版本(通常是13)。

      • (可选)Sec-WebSocket-Protocol:客户端可以声明它支持的子协议。

      • (可选)Origin:表明请求的来源域,用于服务器进行跨域安全检查。

    • 服务器响应

      • 如果服务器支持WebSocket并且同意升级,它会返回一个特殊的HTTP响应,状态码为 101 Switching Protocols

      • Upgrade: websocket 头部:确认升级到WebSocket协议。

      • Connection: Upgrade 头部:确认连接类型升级。

      • Sec-WebSocket-Accept 头部:服务器将客户端发送的Sec-WebSocket-Key与一个固定的"魔法字符串"(258EAFA5-E914-47DA-95CA-C5AB0DC85B11)拼接后,计算SHA-1哈希,然后进行Base64编码,得到的值作为这个头部的内容返回。客户端会验证这个值,以确认服务器确实理解WebSocket协议。

      • (可选)Sec-WebSocket-Protocol:如果服务器从客户端声明的子协议中选择了一个,会通过这个头部返回。

  2. 数据传输阶段 (Data Transfer) - 基于WebSocket帧

    • 连接升级成功:一旦握手成功,底层的TCP连接就不再用于HTTP通信了,而是转为WebSocket协议进行数据传输。

    • 数据帧 (Frames):WebSocket的数据传输是以“帧”(Frame)为单位的。每一条消息(无论是文本还是二进制)都会被分割成一个或多个帧进行传输。

    • 帧的结构:每个WebSocket帧都有一个标准的结构,包含:

      • FIN位 (Final Fragment bit):标记这是否是消息的最后一个分片。

      • RSV1, RSV2, RSV3位 (Reserved bits):保留位,用于未来的扩展,通常为0。

      • Opcode (操作码):指示帧的类型,例如:

        • 0x0:Continuation Frame (连续帧,表示这是一个消息的后续分片)

        • 0x1:Text Frame (文本帧)

        • 0x2:Binary Frame (二进制帧)

        • 0x8:Connection Close Frame (关闭连接帧)

        • 0x9:Ping Frame (Ping帧,用于心跳)

        • 0xA:Pong Frame (Pong帧,Ping的响应)

      • Mask位 (Masking bit):如果为1,表示Payload Data是经过掩码处理的。从客户端发送到服务器的所有帧,其Mask位必须为1,并且Payload Data必须使用一个32位的掩码密钥进行异或(XOR)处理。 这是为了防止代理服务器缓存攻击。服务器发送到客户端的帧,Mask位必须为0,且Payload Data不进行掩码。

      • Payload length (载荷长度):指示Payload Data的长度。

      • Masking-key (掩码密钥):如果Mask位为1,则这里包含32位的掩码密钥。

      • Payload Data (载荷数据):实际传输的数据(文本或二进制),可能经过掩码处理。

    • 消息的重组:如果一条消息被分割成多个帧,接收方需要根据FIN位和Opcode来将这些帧重新组装成完整的消息。

  3. 连接关闭阶段 (Closing Handshake)

    • WebSocket连接的关闭也有一个定义的握手过程。

    • 任何一方(客户端或服务器)都可以发起关闭请求,通过发送一个Opcode为0x8的Close帧。

    • 收到Close帧的一方,通常会回复一个Close帧作为确认,然后双方关闭TCP连接。

    • Close帧中可以包含一个状态码和可选的关闭原因。

WebSocket的优势:

  • 真正的双向通信:客户端和服务器可以同时发送数据。

  • 低延迟:一旦连接建立,后续数据传输不需要每次都进行HTTP握手,减少了开销。

  • 减少头部开销:WebSocket帧的头部相比HTTP请求/响应头部小得多。

  • 更好的带宽利用率:避免了轮询等方式产生的无效请求。

  • 事件驱动:非常适合构建事件驱动的实时应用。

安全性考虑:

  • WSS (WebSocket Secure):WebSocket可以使用TLS/SSL进行加密传输(通过wss:// URL),与HTTPS类似,保证了数据的机密性和完整性。

  • Origin校验:服务器可以检查握手请求中的Origin头部,以防止跨站WebSocket劫持。

  • 客户端掩码:如前所述,客户端发送的帧需要进行掩码,以防止代理缓存攻击。

总结来说,WebSocket通过一次HTTP握手将连接升级,然后在该TCP连接上使用自定义的帧协议进行全双工、低延迟的数据传输,非常适合需要实时、双向通信的Web应用场景。教程中用它来实现协同编辑的实时操作同步,正是利用了其这些核心优势。

4、websocket如何保持长连接?

好的,面试官。WebSocket能够保持长连接,主要是基于以下几个层面的机制和特性,这与传统的短连接HTTP协议有显著不同:

1. 底层TCP连接的持久性:

  • 握手后的TCP复用:WebSocket的初始连接是通过HTTP协议完成的“升级”握手。一旦这个握手成功(服务器返回101 Switching Protocols),底层的TCP连接就被保留下来并被WebSocket协议接管

  • 不再是请求-响应后关闭:与HTTP/1.0或HTTP/1.1(非Keep-Alive或Keep-Alive超时)不同,这个TCP连接在WebSocket握手成功后,不会在一次消息交换后就关闭。它会一直保持打开状态,直到客户端或服务器明确发起关闭握手,或者网络发生中断。

2. WebSocket协议自身的设计:

  • 面向连接的协议:WebSocket协议本身就是设计为一种有状态的、面向连接的协议。它的整个生命周期都依赖于这个持久的TCP连接。

  • 持续的数据帧交换:在连接保持期间,客户端和服务器可以随时通过这个连接互相发送WebSocket数据帧,而不需要为每一条消息重新建立连接。

3. 心跳机制 (Heartbeat Mechanism) - 应用层面或协议层面:

虽然TCP连接本身可以保持打开,但长时间没有数据传输的TCP连接可能会被网络中的某些中间设备(如NAT网关、防火墙、负载均衡器)视为空闲连接而被超时关闭。为了防止这种情况,并确保双方都能感知到连接的活性,通常会采用心跳机制:

  • 应用层心跳

    • 这是最常见的方式。客户端和服务器约定好,定期(例如每隔几十秒)由一方(通常是客户端)发送一个特殊的心跳消息(例如一个空的文本帧,或者一个特定内容的JSON消息,或者一个WebSocket的Ping帧)。

    • 另一方收到心跳消息后,回复一个确认消息(例如一个Pong帧或特定的响应消息)。

    • 作用

      1. 保持连接活跃:通过定期的数据传输,告诉中间网络设备这个连接不是空闲的,不要关闭它。

      2. 检测连接断开:如果一方在预设的时间内没有收到对方的心跳或心跳响应,就可以判断连接可能已经断开,从而进行相应的清理或重连操作。

  • WebSocket协议层面的Ping/Pong帧

    • WebSocket协议本身定义了Ping帧 (Opcode 0x9)Pong帧 (Opcode 0xA)

    • 一方可以发送Ping帧,另一方收到后应尽可能快地回复一个Pong帧。Pong帧的载荷数据通常与它响应的Ping帧的载荷数据相同。

    • 这些帧是WebSocket协议规范的一部分,可以直接用于实现心跳。

    • 许多WebSocket库和服务器都内置了对Ping/Pong帧的支持。

    • 教程中在介绍Disruptor优化时,提到了“Spring WebSocket默认是同步处理,如果某个消息处理耗时比较长,那么后面的消息(比如心跳检测)可能被阻塞”,这间接说明了心跳机制的存在或必要性。

4. TCP Keepalive (TCP层面的机制,可选但有帮助):

  • TCP协议自身也有一个Keepalive机制。当TCP连接长时间空闲时,操作系统内核可以配置为定期发送TCP Keepalive探测包到对端。

  • 如果对端没有响应(例如,因为网络中断或对端主机崩溃),内核会认为连接已死,并通知上层应用。

  • 与WebSocket心跳的区别

    • TCP Keepalive是操作系统内核层面的,对应用透明。其探测间隔通常较长(例如默认2小时),且配置起来不如应用层心跳灵活。

    • WebSocket应用层心跳或Ping/Pong帧则由应用控制,间隔可以更短,能更快地感知到连接问题,并且可以携带应用层面的信息。

  • TCP Keepalive可以作为WebSocket心跳的一个补充,但不能完全替代应用层心跳,因为应用层心跳更能反映应用逻辑的连通性。

总结WebSocket如何保持长连接:

  1. HTTP握手升级:将一个HTTP连接转换为持久的WebSocket连接,底层的TCP连接被复用且不主动关闭。

  2. 协议设计:WebSocket协议本身就是面向连接的,支持在已建立的连接上持续双向传输数据帧。

  3. 心跳机制(关键):通过客户端和服务器之间定期发送和响应心跳消息(可以是应用自定义的,也可以是协议层面的Ping/Pong帧),来:

    • 防止网络中间设备因超时而关闭空闲连接。

    • 及时检测到连接的非正常断开。

  4. (可选辅助) TCP Keepalive:操作系统层面的TCP连接保活机制。

通过这些机制的协同工作,WebSocket连接能够有效地保持长时间的开放状态,从而实现高效的实时双向通信。在教程的协同编辑场景中,这个长连接是用户操作能够被实时广播给其他协作者的基础。