【Linux 网络基础】WebSockets 技术指南

WebSockets 技术指南

本文档适合开发与架构参考使用,包含技术概述、协议细节、实现方案、应用场景、性能优化、兼容性与 RFC 链接。

目录

技术概述

  • 定义:WebSockets 是建立在单个 TCP 连接上的全双工通信协议,使客户端与服务器能够低延迟、双向实时传输数据。
  • 相对 HTTP 轮询:
    • 轮询优点:兼容性好、易部署;缺点:额外请求开销、延迟大、服务端推送困难。
    • WebSockets 优点:单连接双向实时、消息头小、延迟低;缺点:需后端长期持久连接管理、对代理与负载均衡有特殊要求。
  • 协议前缀:
    • ws:// 不加密,适用于受信局域网或非敏感场景。
    • wss:// 通过 TLS 加密,提供机密性与完整性,适用于公网与敏感数据。

协议细节

握手过程(HTTP Upgrade)

  • 客户端通过 HTTP(S) 发起 Upgrade 请求,服务器返回 101 Switching Protocols 并升级到 WebSocket。

  • 请求示例:

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

  • 响应示例:

    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
    Sec-WebSocket-Protocol: chat

  • 关键点:

    • Sec-WebSocket-Key 与服务器计算的 Sec-WebSocket-Accept(基于 GUID 拼接后 SHA-1 再 Base64)。
    • 可选 Sec-WebSocket-Protocol 用于子协议协商;Origin 头建议服务端验证以防跨站连接。

数据帧格式

  • 帧头:
    • FIN(1bit):是否为消息最后一个片段。
    • RSV1--RSV3(3bit):扩展保留位,默认应为 0;压缩扩展可能使用 RSV1
    • Opcode(4bit):0x1 文本、0x2 二进制、0x9 Ping、0xA Pong、0x0 继续帧、0x8 关闭。
    • Mask(1bit):客户端发送必须置 1,含 32bit mask;服务器发送通常为 0。
    • Payload len:7bits 或扩展 16/64bits。
    • Masking-key:客户端帧包含,用于对负载做异或掩码。
  • 负载:文本以 UTF-8 编码;二进制为不透明字节流。消息可由多个片段组成,最终片段 FIN=1

心跳机制(Ping/Pong)

  • Ping/Pong 是协议级心跳与保活。服务器通常定时发送 Ping,客户端收到后自动回复 Pong
  • 浏览器 API 不直接提供 Ping 帧发送接口,客户端可采用应用层心跳消息作为替代。

实现方案

Linux 客户端(libwebsockets)

c 复制代码
#include <libwebsockets.h>

static int cb_client(struct lws *wsi, enum lws_callback_reasons reason,
                     void *user, void *in, size_t len) {
  switch (reason) {
    case LWS_CALLBACK_CLIENT_ESTABLISHED:
      lws_callback_on_writable(wsi);
      break;
    case LWS_CALLBACK_CLIENT_WRITEABLE: {
      unsigned char buf[LWS_PRE + 128];
      unsigned char *p = &buf[LWS_PRE];
      size_t n = lws_snprintf((char*)p, 128, "hello");
      lws_write(wsi, p, n, LWS_WRITE_TEXT);
      break;
    }
    case LWS_CALLBACK_CLIENT_RECEIVE:
      // 处理服务器返回数据(in/len)
      break;
    case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
      // 连接错误处理
      break;
    default:
      break;
  }
  return 0;
}

static const struct lws_protocols protos[] = {
  { "echo", cb_client, 0, 4096 },
  { NULL, NULL, 0, 0 }
};

int main() {
  struct lws_context_creation_info info = {0};
  info.port = CONTEXT_PORT_NO_LISTEN; // 客户端不监听
  info.protocols = protos;
  info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; // 允许 TLS 初始化
  // 指定根 CA(验证 wss 服务端证书),依据系统路径调整
  info.client_ssl_ca_filepath = "/etc/ssl/certs/ca-certificates.crt";

  struct lws_context *ctx = lws_create_context(&info);
  if (!ctx) return 1;

  struct lws_client_connect_info cc = {0};
  cc.context = ctx;
  cc.address = "example.com"; // 服务器地址
  cc.port = 443;               // wss 端口
  cc.path = "/ws";            // 路径
  cc.protocol = "echo";        // 子协议
  cc.host = cc.address;        // SNI/Host
  cc.origin = "https://example.com";
  cc.ssl_connection = LWS_USE_SSL; // 启用 TLS(wss://)

  struct lws *wsi = lws_client_connect_via_info(&cc);
  if (!wsi) return 1;

  while (lws_service(ctx, 0) >= 0) {}
  lws_context_destroy(ctx);
  return 0;
}
  • 构建示例:gcc -o lws_client client.c -lwebsockets(按后端可能需要 -lssl -lcrypto 或 mbedTLS 依赖)。
  • 心跳:libwebsockets 按协议自动处理 Ping/Pong;应用可通过定时器实现业务心跳与超时清理。

Linux 服务端(libwebsockets/Nginx 反向代理)

  • 基于 libwebsockets 的最小服务器:
c 复制代码
#include <libwebsockets.h>

static int cb_echo(struct lws *wsi, enum lws_callback_reasons reason,
                   void *user, void *in, size_t len) {
  switch (reason) {
    case LWS_CALLBACK_ESTABLISHED:
      break;
    case LWS_CALLBACK_RECEIVE:
      lws_callback_on_writable(wsi);
      break;
    case LWS_CALLBACK_SERVER_WRITEABLE: {
      unsigned char buf[LWS_PRE + 1024];
      unsigned char *p = &buf[LWS_PRE];
      size_t n = lws_snprintf((char*)p, 1024, "pong");
      lws_write(wsi, p, n, LWS_WRITE_TEXT);
      break;
    }
    default:
      break;
  }
  return 0;
}

static const struct lws_protocols protos[] = {
  { "echo", cb_echo, 0, 4096 },
  { NULL, NULL, 0, 0 }
};

int main() {
  struct lws_context_creation_info info = {0};
  info.port = 9000;            // 监听端口(ws://)
  info.protocols = protos;
  struct lws_context *ctx = lws_create_context(&info);
  if (!ctx) return 1;
  while (lws_service(ctx, 0) >= 0) {}
  lws_context_destroy(ctx);
  return 0;
}
  • Nginx 反向代理(支持 WebSocket Upgrade 与 wss 终止):
nginx 复制代码
server {
  listen 443 ssl;
  server_name example.com;
  ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

  location /ws {
    proxy_pass http://127.0.0.1:9000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;
  }
}

安全考虑

  • 强制使用 wss:// 于公网与敏感数据传输,启用现代 TLS(TLS 1.2/1.3)。
  • 验证 Origin 头并实施白名单,防止跨站 WebSocket 滥用。
  • 认证与授权:在握手阶段使用 Cookie/Token/自定义头;建立后在应用层维持会话态与权限校验。
  • 资源配额与限速:限制每连接消息大小与速率,防止 DoS。
  • 压缩安全:启用 permessage-deflate 时注意潜在 CRIME/BREACH 类泄露风险,避免在同连接内混合敏感与可控输入。

应用场景

  • 实时聊天:多人房间、私聊、消息既时达。
  • 在线协作:文档/白板/音视频信令等状态同步。
  • 金融行情推送:高频低延迟广播与个性化订阅。

性能优化

  • 连接复用:在同域与同用户场景,复用单连接承载多通道(子协议或应用层路由),减少连接数量。
  • 二进制传输:使用 ArrayBuffer/TypedArray 降低序列化开销;结构化数据建议 Protocol Buffer/FlatBuffers。
  • 压缩扩展:启用 permessage-deflate(RFC 7692)在大消息场景降低带宽;结合分片与批处理。
  • 回压与批量:实现发送队列与背压处理,聚合多条消息后统一写出,降低系统调用次数。
  • 心跳与超时:合理设置服务器 Ping 与连接空闲超时,及时清理断链。

兼容性支持

  • Chrome 16+、Firefox 11+、Safari 6+、Edge 12+、现代移动浏览器均支持 RFC 6455 WebSocket。
  • 代理与负载均衡需支持 HTTP Upgrade 与长连接(Nginx、HAProxy、Envoy 均可通过配置支持)。

RFC 参考链接

握手流程示意图

Browser Server HTTP GET + Upgrade: websocket 101 Switching Protocols 升级为 WebSocket, 建立双向通道 Frames (Text/Binary) Frames (Text/Binary) Ping Pong Browser Server


相关推荐
司铭鸿2 小时前
化学式解析的算法之美:从原子计数到栈的巧妙运用
linux·运维·服务器·算法·动态规划·代理模式·哈希算法
专家大圣2 小时前
告别局域网束缚!飞牛云 NAS+cpolar 让远程管理更简单
开发语言·网络·内网穿透·cpolar
代码AC不AC2 小时前
【Linux】调试器 gdb / cgdb
linux·gdb·调试器·cgdb
last demo2 小时前
MariaDB 数据库管理
linux·运维·服务器·数据库·php·mariadb
生信大表哥3 小时前
Python单细胞分析-基于leiden算法的降维聚类
linux·python·算法·生信·数信院生信服务器·生信云服务器
swanwei3 小时前
2025年11月22-23日互联网技术热点TOP3及影响分析(AI增量训练框架开源)
网络·人工智能·程序人生·安全·百度
x***01063 小时前
SQL 注入漏洞原理以及修复方法
网络·数据库·sql
xixixi777773 小时前
3GPP核心网的演进:是一条清晰的去电信化和IT化道路
网络·协议·通信·3gpp
特种加菲猫5 小时前
用户数据报协议(UDP)详解
网络·网络协议·udp