Skip to content

现代应用与实时协议

应用层协议定义消息结构、交互顺序和错误语义。选择协议时,不能只比较名称,还要明确传输基础、消息方向、可靠性、恢复能力和基础设施兼容性。

TLS 1.3:安全通道

TLS 同时解决三个问题:

  • 机密性:旁观者不能直接读取内容。
  • 完整性:报文被篡改时能够被检测。
  • 身份认证:证书把域名与公钥身份绑定。

TLS 保护两端之间的传输,不能证明服务器业务逻辑安全,也不能阻止已控制终端或服务器的攻击者读取明文。

握手主线

  1. 客户端发送 ClientHello,包含版本、算法、随机数、SNI、ALPN 和临时密钥共享。
  2. 服务器返回 ServerHello 并选择参数。
  3. 双方使用临时密钥交换材料计算相同共享秘密。
  4. 服务器发送证书链和握手签名,证明持有证书私钥。
  5. 客户端验证域名、有效期、用途、签名链和本地信任根。
  6. 双方确认握手 transcript,开始传输加密应用数据。

SNI 让同一 IP 上的服务器选择正确证书;ALPN 用于协商 http/1.1h2 等应用协议。临时密钥交换提供前向保密,即使证书私钥以后泄漏,过去抓取的会话也不应被直接解密。

bash
openssl s_client -connect example.com:443 \
  -servername example.com \
  -alpn h2 -showcerts

证书过期、系统时间错误、证书链缺少中间证书、SNI 不匹配和算法不兼容都会导致握手失败。

HTTP/1.1:消息与连接复用

HTTP/1.1 请求由请求行、Header、空行和可选 Body 组成。响应由状态行、Header、空行和 Body 组成。

http
POST /orders HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 28

{"sku":"A100","count":2}

TCP 没有消息边界,HTTP 必须自己判断 Body 在哪里结束。常见方式包括 Content-LengthTransfer-Encoding: chunked、无 Body 状态码,以及连接关闭。

代理链前后若对冲突的长度字段采用不同解释,可能形成 Request Smuggling。因此网关应拒绝歧义消息,而不是猜测客户端意图。

长连接与队头阻塞

HTTP/1.1 默认可以复用 TCP 连接,避免每个请求重新握手。Pipeline 理论上允许连续发请求,但响应必须按顺序返回,一个慢响应会阻塞后续响应。客户端通常建立多个连接,或升级到 HTTP/2。

缓存

Cache-Control 决定缓存策略,ETagIf-None-Match 用于验证内容是否变化。共享缓存必须正确处理 Vary、身份信息和私有响应,否则可能把一个用户的数据返回给另一个用户。

HTTP/2:Frame 与 Stream

HTTP/2 保留方法、状态码和缓存语义,改变线上表达:消息被拆成二进制 Frame,每个请求响应占用一个 Stream。

Frame作用
HEADERS携带压缩后的 Header Block
DATA携带消息 Body
SETTINGS声明并发流、窗口和帧大小等参数
WINDOW_UPDATE增加连接或 Stream 的流控窗口
RST_STREAM终止单条 Stream
GOAWAY优雅停止创建新 Stream

不同 Stream 的 Frame 可以交错传输,接收端按 Stream ID 重组。HPACK 通过静态表、动态表和索引减少重复 Header。

HTTP/2 在连接与 Stream 两级维护流量控制窗口。但所有 Frame 最终仍位于一条 TCP 字节流中;底层 TCP Segment 丢失时,后续所有 Stream 的字节都要等待缺口补齐。

bash
curl -v --http2 https://example.com/
nghttp -nv https://example.com/

QUIC 与 HTTP/3

HTTP/3 保留 HTTP 语义,使用 QUIC 取代 TCP。QUIC 在 UDP 之上实现安全连接、可靠传输、多路 Stream、拥塞控制和连接迁移。

QUIC Packet 与 Stream

一个 UDP Datagram 可以包含多个 QUIC Packet,一个 QUIC Packet 可以包含多个 Frame。STREAM Frame 携带 Stream ID、Offset 和数据。

每条 Stream 有自己的有序字节空间。某条 Stream 丢失数据时,只阻塞依赖该 Offset 的 Stream,其他 Stream 可以继续交付。所有 Stream 仍共享连接级拥塞控制,因此丢包会影响整体发送速度,但不会制造 TCP 那种全局交付阻塞。

握手与恢复

QUIC 把 TLS 1.3 握手放在 CRYPTO Frame 中,首次连接通常约 1-RTT 建立安全通道。恢复会话可以发送 0-RTT 数据,但零往返数据可能被重放,只适合明确设计为幂等的操作。

连接迁移

QUIC 使用 Connection ID 维持连接身份。客户端从 Wi-Fi 切换到蜂窝网络后,可以验证新路径并继续已有连接,不必只依赖固定四元组。

bash
curl -I --http3 https://example.com/
sudo tcpdump -nn 'udp port 443'

HTTP/3 依赖 UDP 可达。UDP 被阻断时,客户端通常回退 HTTP/2。验证服务是否真正使用 HTTP/3,要检查 ALPN、Alt-Svc 和实际 UDP 流量,不能只看服务器配置文件。

WebSocket:全双工消息

WebSocket 先通过 HTTP/1.1 Upgrade 握手:

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

服务器接受后返回 101 Switching Protocols。此后同一 TCP 连接按 WebSocket Frame 传输,不再是普通 HTTP 消息。

Frame 包含 FIN、Opcode、Mask、Payload Length 和可选 Masking Key。Text 与 Binary 表示消息类型,Continuation 用于分片。客户端到服务器的 Frame 必须 Mask,但 Mask 不是加密;WSS 的安全性来自 TLS。

生产设计

  • Ping/Pong 检测应用层通道活性。
  • 发送队列必须有界,慢客户端不能无限积压内存。
  • 断线重连应带最后确认序号,由服务器补发可恢复事件。
  • 多节点网关需要通过 Broker 把消息投递到用户实际连接的节点。
  • 代理要支持 Upgrade,并设置合理空闲超时。

WebSocket 只保证 TCP 字节到达,不保证业务事件已经落库或处理。业务层仍需要消息 ID、ACK、幂等和去重。

详细对照见 HTTP 与 WebSocket 的区别

SSE 与长轮询

SSE 使用 text/event-stream 持续发送 UTF-8 事件:

text
event: order-updated
id: 1842
retry: 3000
data: {"status":"paid"}

浏览器 EventSource 会自动重连,并通过 Last-Event-ID 携带恢复位置。SSE 适合通知、日志和生成式文本流。客户端上行仍使用普通 HTTP。

反向代理必须关闭或缩短响应缓冲,否则服务器已经发送的事件会被攒成大块。服务端还要定期发送注释心跳,避免中间设备按空闲连接关闭通道。

长轮询则把一个普通 HTTP 请求挂起,直到有事件或超时,返回后立即创建下一次请求。它兼容性强,但每轮都有 Header 和重建窗口。

WebTransport

WebTransport 基于 HTTP/3,在一个会话中同时提供:

  • 可靠双向 Stream。
  • 可靠单向 Stream。
  • 不保证可靠和顺序的 Datagram。

命令和关键状态可以走 Stream,过期即无价值的位置更新可以走 Datagram。它适合需要多条独立流和低延迟消息的浏览器应用,但部署前必须确认浏览器、网关和 UDP 网络支持。

gRPC

gRPC 使用 .proto 定义服务与消息,生成客户端 Stub 和服务端接口。Protobuf 在线上依赖字段编号而不是字段名;删除字段后不得复用旧编号。

一次 RPC 通常对应一条 HTTP/2 Stream:

text
HEADERS  :path=/package.Service/Method
DATA     compressed-flag + length + protobuf
TRAILERS grpc-status + grpc-message

HTTP 状态为 200 不代表 RPC 成功,最终状态通常位于 Trailers。

四种调用

类型请求响应场景
Unary11普通查询与命令
Server Streaming1多条持续订阅
Client Streaming多条1批量上传
Bidirectional多条多条双向实时协作

每次调用应设置 Deadline,并把剩余预算向下游传播。自动重试只能用于幂等操作,并受总时间、次数和并发预算限制。客户端、网关和 SDK 同时重试会形成流量放大。

bash
grpcurl -plaintext localhost:50051 list
grpcurl -plaintext -d '{"id":1}' localhost:50051 demo.User/Get

WebRTC

WebRTC 是一组实时通信机制,而不是单一协议:

  1. 业务信令交换 SDP Offer、Answer 和 ICE Candidate。
  2. ICE 收集 Host、STUN 反射和 TURN 中继 Candidate。
  3. 连通检测选择真正可用的 Candidate Pair。
  4. DTLS 协商密钥,SRTP 加密音视频 RTP。
  5. RTCP 反馈丢包、抖动和带宽估计。

STUN 帮助端点观察 NAT 映射,却不能保证所有 NAT 都能打洞。直连失败时,TURN 承担完整上下行中继流量,需要监控 Relay 占比、地区带宽和分配失败。

实时媒体不会无限等待重传。接收端使用抖动缓冲,发送端根据 NACK、PLI 和带宽估计调整重传、关键帧、码率、分辨率与帧率。

多人会议通常使用 SFU:每个端点上传一路,服务器按订阅和带宽选择性转发。排查时应查看 Candidate 类型、RTT、丢包、Jitter、发送码率和解码帧率。

MQTT 与 CoAP

MQTT 通过 Broker 在 Publisher 与 Subscriber 之间路由 Topic。QoS 描述协议交付尝试:

QoS语义代价
0至多一次无确认,可能丢失
1至少一次需要确认,可能重复
2协议会话内恰好一次流程状态和交互最多

业务副作用仍需幂等。Retained Message 保存 Topic 最新值,不是历史消息队列;Will Message 用于异常离线通知;Session Expiry 决定断线后保留订阅和未确认消息多久。

CoAP 在 UDP 上提供紧凑的 REST 语义,支持 Confirmable 消息、Observe 和 Block-Wise 分块,适合资源受限设备。设备网常通过边缘网关聚合、缓存并转换为 MQTT 或 HTTPS 上云。

选型矩阵

需求首选方向必须补充的工程机制
REST APIHTTP/2 或 HTTP/3超时、幂等、缓存、限流
单向事件SSE事件 ID、补发、代理缓冲
双向业务消息WebSocket心跳、背压、重连、ACK
多流与低延迟 DatagramWebTransport能力探测、UDP 回退
内部 RPCgRPCDeadline、兼容、重试预算
音视频WebRTCTURN、拥塞控制、媒体指标
设备遥测MQTT会话、QoS、设备身份

选择协议后还要进入 容量、并发与性能,把连接、消息和资源消耗转化为可验证模型。

别急,先让缓存热一下。