WebSocket协议本身不支持文件传输,需在应用层实现分片、校验、序号管理及幂等写入等机制。

WebSocket在C++里不直接支持文件传输
WebSocket协议本身只定义了消息帧(text/binary),没有内置文件分块、校验、断点续传等机制。C++中用libwebsockets、Boost.Beast或uWebSockets实现的都是“二进制消息收发”,你要传文件,得自己拆包、加元数据、处理粘包/丢包。
用Boost.Beast发送大文件必须分片且带header
直接write一个几百MB的std::vector<uint8_t>会触发内存暴涨甚至OOM,而且服务端无法区分这是文件还是普通二进制流。正确做法是:先发一段JSON header描述文件名、大小、分片序号,再按固定大小(比如64KB)分片发送。
- 每片用
websocket::stream::write发,设binary = true - header必须用
websocket::frame_type::text,否则接收端可能解析失败 - 分片间不要sleep——依赖TCP流控,但要检查
error_code是否为boost::beast::error::timeout - 最后一片发完后,建议再发一个
{"type":"eof","id":123}text帧,避免接收端死等
libwebsockets客户端容易卡在send返回0
调用lws_write返回0不是成功,而是“暂时没空间写”,尤其在高吞吐下很常见。它不阻塞,也不自动重试,你得轮询lws_callback_on_writable并配合lws_callback_as_writeable手动触发可写回调。
- 别在单次回调里连续调用
lws_write多次——很可能只写出第一片就返回0 - 维护一个
std::queue<std::vector<uint8_t>>做待发缓冲,每次回调只取一片发 -
lws_set_socket_option设LWS_SOCKOPT_SET_TCP_NODELAY能减少小包延迟,但对大文件影响有限 - 注意
libwebsockets默认最大帧长是128KB,超限会静默截断,需改编译时LWS_MAX_SOCKET_IO_BUF
接收端必须处理跨帧边界和零长度payload
WebSocket规范允许一个应用消息被拆成多个CONTINUATION帧,而某些服务端(如Nginx proxy、Cloudflare)会在中间插入空帧或合并小帧。你不能假设read一次就拿到完整分片。
立即学习“C++免费学习笔记(深入)”;
- 用
boost::beast::websocket::stream::read时,检查msg.opcode()是否为websocket::frame_type::binary,忽略continuation帧的opcode - 收到
frame_size == 0时不要panic——可能是心跳帧或代理注入的keepalive,跳过即可 - 文件内容拼接必须基于分片序号(从header里解析),不能按接收顺序盲拼——网络乱序真实存在
- 建议在每片末尾加4字节CRC32校验,比全文件MD5更早发现传输损坏
真正麻烦的不是发和收,是两边对“分片完成”的判定逻辑不一致:比如客户端认为发完了,服务端还在等下一帧;或者服务端已写入磁盘,客户端因超时重发导致重复。这类问题只能靠应用层协议+唯一请求ID+幂等写入解决,WebSocket本身不保这个。


















