connection->send是同步阻塞调用,仅适用于调试、低频指令或极低并发场景;高并发下易导致响应延迟或超时,应改用异步发送或事件驱动队列。

connection->send 是同步阻塞的,别在高并发场景直接用
connection->send 本质是同步调用,会卡住当前线程直到消息写入底层 socket 缓冲区(或失败)。在 Web 服务器里,尤其用在 HTTP 长连接或 WebSocket 连接池中时,它容易拖垮吞吐量。
- 常见错误现象:
send调用后接口响应明显变慢,甚至超时;日志里反复出现EAGAIN或EWOULDBLOCK - 适用场景:调试阶段快速验证、低频管理指令(如单次心跳确认)、客户端连接数极低(
- 性能影响:每多一次
send就多一次系统调用开销;若对方网络卡顿或接收端处理慢,你的线程就干等 - 替代方案优先考虑:
connection->async_send(如 Boost.Beast)、ws.send(..., {binary: false})(ws 库)、或封装成事件驱动队列
想发给“某一个”客户端?先确认你拿到的是真实 connectionId
很多开发者以为 connection->id() 或 socket.id 天然唯一且稳定,其实它只在当前连接生命周期内有效——断连重连后 ID 必然变化,且不同框架生成规则完全不同。
- 常见错误现象:向旧
connectionId发送消息无响应;用户刷新页面后收不到后续推送;后台日志显示 “client not found” - 必须做的两件事:① 在
on_connect时把connectionId和业务标识(如 user_id)绑定存入内存缓存或 Redis;② 在on_disconnect时及时清理该映射 - 参数差异注意:
SignalR的Clients.Client(connectionId)要求 ID 完全匹配;socket.io的io.to(socket.id).emit()实际是广播到房间,不是直连,需确保没误建同名房间 - 兼容性坑:
uWebSockets.js的res.send()不接受 connectionId,得靠app.publish()+ 主题路由模拟点对点
send 失败不等于丢消息,但默认不会重试
send 返回 false 或抛出异常,只说明这次写入失败,不代表客户端永远收不到——可能只是 TCP 缓冲区满、对方刚断网、或 SSL 握手未完成。框架几乎都不自带重试逻辑。
- 常见错误现象:前端偶尔收不到关键指令(如权限变更通知),查服务端日志发现
send failed: broken pipe,但没做任何补偿 - 必须判断的返回值:
send返回size_t(实际发送字节数),若小于预期长度,说明部分未发出;返回 -1 且errno == EAGAIN表示可重试 - 轻量级补救建议:对非实时强依赖消息(如状态快照),可将失败消息 + connectionId 写入 Redis List,由后台定时任务扫描重推;对实时指令(如踢下线),应改用带 ACK 机制的协议层(如 MQTT QoS=1)
- 别踩的坑:在
catch块里直接sleep(1)后重 send —— 这会锁死整个协程/线程,放大雪崩风险
二进制还是文本?send 前不检查 content-type 很容易前端解析失败
很多 C++/Rust 服务端默认用 send 推原始字节流,但前端 WebSocket onmessage 事件的 event.data 类型取决于服务端是否设置了 binaryType 和帧标志位。不一致就会导致乱码或 Unexpected token 错误。
- 常见错误现象:JS 控制台报
DOMException: Failed to execute 'postMessage' on 'Window': An object could not be cloned;或者收到一串乱码字符串而非 JSON 对象 - 实操要点:
send前显式指定类型:用std::string传文本,用std::vector<uint8_t></uint8_t>或boost::asio::const_buffer传二进制;Node.js 的ws库需配ws.send(data, { binary: true }) - 兼容性影响:Chrome/Firefox 对 binaryType 默认为
"blob",但 Safari 旧版本要求"arraybuffer";若你用JSON.stringify后 send,务必确保前端用JSON.parse(event.data),而不是直接当对象用









