Swoole的send()不支持批量发送,需手动拼包;真正批量应使用协程客户端sendco()并发发送,并通过getSocket()和socket_last_error()排查底层错误。

send() 不能直接批量发,得自己攒包
很多人以为 Swoole\Client 的 send() 能像 stream_socket_sendto() 那样一次塞多个数据包,实际不是——它每次只发一个完整 buffer。TCP 层不保证“一次 send 对应一次 recv”,但 Swoole 客户端的 send() 本身也不聚合、不缓冲、不排队。
常见错误现象:send() 连续调用 10 次,服务端收到乱序、粘包,或部分丢失(尤其在高并发短连接场景)。
- 真正需要“批量”,得手动把多条业务数据序列化后拼成一个
string再send() - 若用
EOF或LengthField协议,必须确保拼包时严格遵守分隔规则,比如每条加"\n"或前置 4 字节长度 - 别依赖
sleep()或usleep()来“等发送完成”——send()返回 true 只代表写入 socket 缓冲区成功,不代表已发出
协程客户端用 sendco() 才能安全并发发多条
同步客户端(Swoole\Client)阻塞发完一条才能发下一条,根本谈不上“批量操作”。真要并发发 100 条,得切到协程客户端 Swoole\Coroutine\Client,配合 sendco()。
使用场景:向同一个后端服务批量上报日志、推送设备指令、补单请求等,要求低延迟、高吞吐、可超时控制。
-
sendco()是协程安全的,可在同个协程里反复调用,也可在不同协程里并发调用(只要 client 实例不共享) - 务必设置
$client->set(['timeout' => 3]),否则某条卡住会拖垮整批 - 别复用同一个
$client实例跨协程发数据——Swoole 会报"Operation not permitted"错误 - 示例:启动 10 个协程,每个调
$client->sendco($data),比串行快 5 倍以上,但要注意服务端承受力
sendfile() 不是批量发送,是零拷贝发文件
看到 “批量” 就想到 sendfile()?这是典型误解。sendfile() 只负责把一个本地文件内容高效推给对端,和“多条业务消息打包发”完全无关。
容易踩的坑:sendfile() 成功只表示内核开始搬运,不保证对方收到;且它不支持加密传输(如 TLS),也不能加协议头或做序列化。
- 仅适用于静态资源下发、大文件透传等场景,比如 CDN 回源、配置文件同步
- 路径必须是绝对路径,相对路径会失败并抛出
"No such file or directory" - 如果文件大于 2GB,在 32 位系统或某些旧内核上可能截断,建议先
filesize()校验 - 别试图用
sendfile()发 JSON 数组或 Protobuf 列表——它不处理应用层逻辑
批量失败时,错误码藏在 getSocket() 里
Swoole 客户端批量操作失败,send() 或 sendco() 很可能静默返回 false,而 getLastError() 只给个笼统的 SWOOLE_ERROR_SOCKET_WRITE,真正原因得挖底层 socket。
关键动作:调 $client->getSocket() 拿到 resource,再用 socket_last_error() 查系统级错误。
- 常见真实错误:
10055(Windows)或11(Linux)表示发送缓冲区满,说明发太快,需限速或加队列 -
32(broken pipe)说明对端已断连,但 client 实例还活着,得主动close()后重建 - 协程里用
socket_last_error()前,确认当前协程仍持有该 socket,否则 resource 已失效 - 别只靠 try/catch——Swoole 多数错误不抛异常,得靠返回值 + 错误码双检
批量这事,表面是发得多,实际是节奏、边界、状态三者咬合。漏查一次 getSocket(),就可能让整批重试逻辑失效。










