【Linux 网络基础】libwebsockets 技术文档

libwebsockets 技术文档

来源与版本:概述与特性信息参考 https://libwebsockets.org/,以及其 Doxygen/API 文档与示例仓库(v4.4/main)。

目录

概述

  • libwebsockets(LWS)是一个轻量级、纯 C 的网络库,专注于现代网络协议(HTTP/1.x、HTTP/2、WebSocket、Raw TCP/UDP 等)的事件驱动实现,面向非阻塞 I/O 与小内存占用。
  • 支持可选的 TLS 后端(OpenSSL 或 mbedTLS),可在受限设备上通过选择后端来在"性能/内存"上做权衡。
  • 提供"角色(Role)"与"协议(Protocol)"的抽象层,用户通过注册回调处理连接生命周期、收发数据、定时器与错误事件。
  • 默认使用 poll() 事件循环,同时支持集成外部事件库(glib、libuv、libevent、libev),并提供高分辨率定时器抽象。

核心功能与特性

  • 轻量化纯 C 实现:代码体积与依赖可控,适合嵌入式与高性能场景。
  • 多角色支持:
    • http/1.xhttp/2websocketsws-over-h2(服务器端支持)、raw tcp/udp/fileMQTT(客户端或服务端视版本而定)。
    • 角色通过 ops 结构与核心栈解耦,易于扩展新协议实现。
  • 跨平台与可插拔事件循环:默认 poll(),可集成 libuv/libevent/libev/glib。
  • TLS 与安全:支持 OpenSSL/mbedTLS 后端,提供通用 API 访问哈希、RSA、X509 功能;支持客户端证书与服务器验证。
  • 高分辨率定时器:为每个连接提供统一的延时回调机制,屏蔽具体事件库差异。
  • vhost(虚拟主机):在同一上下文中托管多个主机与证书配置,便于多域与多服务实例管理。

架构设计

  • 事件驱动架构:
    • LWS 核心负责 socket 生命周期、TLS 握手、vhost 管理、服务线程、定时器与外部事件库适配。
    • 用户以"协议回调"方式处理各类事件(建立、可写、接收、关闭等),由 LWS 在合适时机分派。
  • 线程模型:
    • 典型用法为单线程事件循环(更简单与可预测);可选"服务线程"或参与外部事件循环以实现并发。
    • 推荐通过事件回调进行异步化,不在回调中进行阻塞操作;如需后台任务,使用队列或其他线程,并在适当时机唤醒连接进入 WRITEABLE
  • 内存管理机制:
    • 每连接(struct lws *wsi)具备协议上下文与缓冲状态;写操作要求预留头部空间(LWS_PRE)以支持协议封装(如 WS 帧、HTTP 头)。
    • LWS 避免过度动态分配,提供环形缓冲与延迟队列等设施;用户应遵循回调中的生命周期与零拷贝原则,减少复制。

软件架构图

Roles HTTP/1.x HTTP/2 WebSockets Raw TCP/UDP/File MQTT User Application Protocol Callbacks LWS Core
socket lifecycle / vhosts / timers Event Loop Adapter poll libuv libevent libev glib TLS Backend OpenSSL mbedTLS Vhosts Listeners Certs / Keys

API 文档概览

上下文与虚拟主机

  • 创建上下文:
c 复制代码
#include <libwebsockets.h>

int main(void) {
  struct lws_context_creation_info info;
  memset(&info, 0, sizeof(info));
  info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; // 可选 TLS 初始化
  struct lws_context *context = lws_create_context(&info);
  if (!context) return 1;

  // 事件循环
  while (1) {
    lws_service(context, 0); // 非阻塞服务,参数为"等待时间"
  }
  lws_context_destroy(context);
  return 0;
}
  • 创建 vhost:
c 复制代码
struct lws_vhost *vhost;
struct lws_context_creation_info info;
struct lws_vhost_creation_info vinfo;
// 填充 info 并创建 context 后...
memset(&vinfo, 0, sizeof(vinfo));
vinfo.port = 8443; // 监听端口
vinfo.protocols = protocols; // 协议数组(见下)
vinfo.ssl_cert_filepath = "/etc/ssl/certs/server.crt";
vinfo.ssl_private_key_filepath = "/etc/ssl/private/server.key";
vhost = lws_create_vhost(context, &vinfo);

协议与回调

  • 定义协议数组与回调:
c 复制代码
static int callback_example(struct lws *wsi, enum lws_callback_reasons reason,
                            void *user, void *in, size_t len) {
  switch (reason) {
    case LWS_CALLBACK_ESTABLISHED: // 服务器端连接建立
      // 初始化每连接状态(user 指向 per-session 数据)
      break;
    case LWS_CALLBACK_RECEIVE: // 收到客户端消息(服务器端)
      // 处理 in/len 数据;如需回复,安排可写
      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 = snprintf((char*)p, 1024, "hello");
      lws_write(wsi, p, n, LWS_WRITE_TEXT);
      break;
    }
    case LWS_CALLBACK_CLOSED: // 连接关闭
      break;
    default:
      break;
  }
  return 0;
}

static const struct lws_protocols protocols[] = {
  { "example-protocol", callback_example, 0, 4096 },
  { NULL, NULL, 0, 0 }
};
  • 回调事件(常见):
    • 服务器端:LWS_CALLBACK_ESTABLISHEDLWS_CALLBACK_RECEIVELWS_CALLBACK_SERVER_WRITEABLELWS_CALLBACK_CLOSED 等。
    • 客户端:LWS_CALLBACK_CLIENT_ESTABLISHEDLWS_CALLBACK_CLIENT_RECEIVELWS_CALLBACK_CLIENT_WRITEABLELWS_CALLBACK_CLIENT_CONNECTION_ERROR 等。
    • HTTP/RAW/TLS 相关:建立、标头处理、超时、心跳、定时器。

连接建立(客户端/服务器)

  • 服务器监听(见 vhost 创建):将 protocols 传入 vhost,即可在端口上接受连接。
  • WebSocket 客户端连接:
c 复制代码
struct lws_client_connect_info ccinfo;
memset(&ccinfo, 0, sizeof(ccinfo));
ccinfo.context = context;
ccinfo.address = "echo.websocket.org"; // 或自定义服务器
ccinfo.port = 443;
ccinfo.path = "/";
ccinfo.ssl_connection = LWS_USE_SSL;
ccinfo.protocol = "example-protocol";
ccinfo.origin = "origin";
ccinfo.pwsi = &wsi; // 可选:获取新建连接
struct lws *wsi = lws_client_connect_via_info(&ccinfo);

消息收发与缓冲

  • lws_write() 需使用带有 LWS_PRE 预留空间的缓冲区,以便库添加协议头(WS 帧/HTTP 头)。
  • 写入流程建议:
    • RECEIVE 中仅处理输入与排队输出,调用 lws_callback_on_writable() 通知框架稍后进入 WRITEABLE
    • WRITEABLE 事件中实际执行 lws_write();遵循回压(backpressure),避免长时间占用回调。
  • 客户端与服务器都存在各自的 *_WRITEABLE 事件;应尽量批量写入、减少系统调用次数。

事件循环与定时器

  • 默认事件循环为 poll();可在编译时/运行时选择集成 libuv/libevent/libev/glib。
  • 高分辨率定时器:每连接可设置延迟回调(计时触发),用于心跳或超时控制;API 依据版本提供统一封装,屏蔽底层事件库差异。

TLS/HTTPS 支持

  • 后端选择:OpenSSL(更快、占用更多内存)或 mbedTLS(更省内存、性能稍逊),官方建议在受限设备使用 mbedTLS。
  • 支持客户端证书与服务器验证;可在 vhost 配置证书路径、私钥路径与验证策略。

使用场景与最佳实践

  • 嵌入式设备:
    • 使用 mbedTLS 后端降低内存占用;采用单线程事件循环减少复杂度。
    • 使用自定义协议或 WebSocket 与云服务交互;开启心跳与应用级重连策略。
  • 网关与边缘计算:
    • 在 vhost 上托管多域服务(HTTP/WS 混合);按协议分离回调与资源限制。
    • 集成 libuv 以更好地与其他异步组件协同运行。
  • 现代 WebSocket 服务:
    • 大量并发连接的推送场景(行情/聊天/通知);合理设置写缓冲与批处理。
    • 使用 ws-over-h2(在服务器端)降低连接成本并改善队头阻塞。
  • 原始传输(Raw TCP/UDP):
    • 通过 Raw 角色快速实现自定义传输;结合 TLS 后端实现加密。

性能指标与优化建议

  • 性能特征(基于官方概述):
    • 轻量级非阻塞事件驱动,可在资源受限设备运行;OpenSSL 后端更快但占用更高,mbedTLS 更省内存。
    • 可插拔事件库使其在不同平台保持稳定与高效。
  • 优化建议(通用工程实践):
    • 使用 WRITEABLE 回调批量写出,减少系统调用;在 RECEIVE 中避免同步重处理。
    • 合理规划缓冲大小,遵循 LWS_PRE;避免在回调里进行阻塞 I/O 或长计算。
    • 结合高分辨率定时器进行心跳/超时管理;降低无效唤醒与忙轮询。
    • 在受限设备选择 mbedTLS;在服务器或高性能环境选择 OpenSSL。
    • libuv/libevent 集成时,统一事件源与资源管理,避免两套循环相互阻塞。
    • 使用 vhost 将不同域与证书隔离,减少共享资源竞争。
    • 调整内核与系统参数(如 TCP_NODELAY、缓冲区限制、FD 上限)以适应高并发。

注:公开的官方站点未列出固定的吞吐/延迟基准表(随版本与平台变化),建议参考对应版本的 Doxygen/示例与社区基准测试结果,并在目标平台上进行实测。

参考资料


附:最小服务器与客户端示例(带注释)

最小服务器(WebSocket)
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);
      // 将数据暂存到 user 中(实际项目需实现环形缓冲/队列)
      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;
  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;
}
最小客户端(WebSocket)
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;
  struct lws_context *ctx = lws_create_context(&info);
  if (!ctx) return 1;

  struct lws_client_connect_info cc = {0};
  cc.context = ctx;
  cc.address = "127.0.0.1";
  cc.port = 9000;
  cc.path = "/";
  cc.protocol = "echo";
  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;
}

相关推荐
2501_9160074725 分钟前
iOS 应用性能测试的工程化流程,构建从指标采集到问题归因的多工具协同测试体系
android·ios·小程序·https·uni-app·iphone·webview
q***518932 分钟前
ubuntu 安装 Redis
linux·redis·ubuntu
TT哇32 分钟前
消息推送机制——WebSocket
java·网络·websocket·网络协议
q***47182 小时前
使用Canal将MySQL数据同步到ES(Linux)
linux·mysql·elasticsearch
Y淑滢潇潇2 小时前
RHCE 防火墙实验
linux·运维·rhce
wadesir3 小时前
当前位置:首页 > 服务器技术 > 正文Linux网络HSRP协议(实现路由器热备份与高可用性的实用指南)
linux·服务器·网络
稻谷君W3 小时前
Ubuntu 远程访问 Win11 WSL2 并固定访问教程
linux·运维·ubuntu
带土13 小时前
4. 两台win11 笔记本局域网内文件传输
网络
wdfk_prog3 小时前
[Linux]学习笔记系列 -- [kernel]workqueue
linux·笔记·学习