libwebsockets 技术文档
来源与版本:概述与特性信息参考 https://libwebsockets.org/,以及其 Doxygen/API 文档与示例仓库(v4.4/main)。
目录
- 概述
- 核心功能与特性
- 架构设计
- 软件架构图
- [API 文档概览](#API 文档概览)
- 上下文与虚拟主机
- 协议与回调
- 连接建立(客户端/服务器)
- 消息收发与缓冲
- 事件循环与定时器
- [TLS/HTTPS 支持](#TLS/HTTPS 支持)
- 使用场景与最佳实践
- 性能指标与优化建议
- 参考资料
概述
- 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.x、http/2、websockets、ws-over-h2(服务器端支持)、raw tcp/udp/file、MQTT(客户端或服务端视版本而定)。- 角色通过 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_ESTABLISHED、LWS_CALLBACK_RECEIVE、LWS_CALLBACK_SERVER_WRITEABLE、LWS_CALLBACK_CLOSED等。 - 客户端:
LWS_CALLBACK_CLIENT_ESTABLISHED、LWS_CALLBACK_CLIENT_RECEIVE、LWS_CALLBACK_CLIENT_WRITEABLE、LWS_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/示例与社区基准测试结果,并在目标平台上进行实测。
参考资料
- 官网概述与下载:https://libwebsockets.org/
- 仓库与示例:https://libwebsockets.org/repo/libwebsockets
- Doxygen/API 文档(按版本选择 v4.4 或 main):官网文档入口与示例链接。
- 事件库说明:官网"Event loop libraries"章节。
- TLS 后端选择与说明:官网"TLS (SSL) support"章节。
附:最小服务器与客户端示例(带注释)
最小服务器(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;
}