Swoole异步客户端需调用connect()或execute()才触发网络行为,因new仅初始化不建连;未连接即send会失败,onConnect前调用send可能因socket未就绪而无效。

Swoole 异步客户端不是靠“多线程”或“协程切换”实现并发,而是基于事件循环 + 非阻塞 I/O + 回调调度,底层完全复用 swoole_event 系统。
为什么 new Swoole\Http\Client 不能直接发请求?
创建实例只是分配内存和初始化状态,并不建立连接。真正触发网络行为的是 execute() 或 connect() 方法 —— 它们会把 socket 设为非阻塞模式,注册到 epoll/kqueue,并绑定读写回调函数。
- 未调用
connect()就调get(),会报错Connection is not established - 若在
onConnect回调外调用send(),实际发送可能失败(socket 还没就绪) - PHP 层的“异步”本质是把控制权交还给
EventLoop,不是立刻执行,这点和curl_multi的轮询模型有根本区别
onConnect、onReceive、onClose 的触发时机和限制
这三个回调由 swClient_onRead/swClient_onWrite 底层函数驱动,不是 PHP 主动调用,也不在用户代码栈中运行。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
-
onConnect在 TCP 握手完成、socket 可写时触发;如果 DNS 解析失败,它根本不会执行,而是走onError -
onReceive每次只收到一个 TCP 包的数据片段,不是完整 HTTP 响应体;需自行拼接或依赖Http\Client内置的 parser -
onClose不代表连接已释放:socket fd 可能还在内核等待 FIN-ACK,PHP 对象此时已被销毁,不能再访问$client->sock
为什么并发 1000 个请求,实际只看到几百个 onConnect?
这不是 Swoole 的 bug,而是受系统级资源限制:每个连接消耗一个 socket fd、临时端口、内核缓冲区。Linux 默认 net.ipv4.ip_local_port_range 是 32768–65535,最多约 32K 临时端口;加上 TIME_WAIT 占用,高频短连接极易打满。
- 解决方法不是调大 ulimit,而是复用连接:
$client->set(['keep_alive' => true]) - 避免在回调里 new 新 client,否则对象生命周期失控,fd 泄漏风险高
- 用
strace -e trace=connect,sendto,recvfrom可验证是否真有连接发出,比看 PHP 日志更可靠
真正难处理的从来不是“怎么发”,而是连接池管理、超时判定(DNS/Connect/Read 各自独立)、以及回调嵌套导致的状态混乱 —— 这些在 Swoole\Coroutine\Http\Client 里被协程透明化了,但原生异步客户端仍得自己扛。

















