最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Swoole中sendwait同步发送的差异
时间:2026-07-07 09:55:57 编辑:袖梨 来源:一聚教程网
send 和 sendwait 并非并列 API,而是同一发送行为在阻塞/非阻塞上下文中的不同表现:前者依赖 socket 模式与上层等待逻辑,后者是 swConnection 内部标识发送等待状态的字段,用于事件循环重试。
send 和 sendwait 不是 Swoole 提供的两个并列 API,而是同一发送行为在不同上下文中的表现逻辑——关键区别在于「连接是否处于阻塞模式」以及「调用方是否主动等待写就绪」。
swConnection_send 是底层统一入口
无论你用的是 swoole_client 同步模式、异步模式,还是协程客户端,最终发数据都会走到 swConnection_send。这个函数本身不做“同步/异步”判断,它只负责调用系统 send() 系统调用:
- 如果 socket 是阻塞的(如
swoole_client同步模式下connect时未设SWOOLE_SOCK_ASYNC),send()会等内核把数据拷进 TCP 发送缓冲区才返回,看起来就是“同步发送” - 如果 socket 是非阻塞的(如 Reactor 线程中所有连接、协程客户端底层),
send()可能立刻返回-1,且errno == EAGAIN或EWOULDBLOCK - 此时真正决定“要不要等”的,不是
send函数本身,而是上层逻辑:比如swClient_tcp_send_sync在遇到EAGAIN时会主动调用swSocket_wait阻塞等待 1 秒;而swConnection_buffer_send(用于 Reactor 线程)则直接标记send_wait = 1并返回,让事件循环下次再试
sendwait 不是公开 API,而是内部状态标识
你在源码里看到的 send_wait = 1,是 swConnection 结构体里的一个字段,用于通知 Reactor:“这个连接当前不可写,别再往它 buffer 里塞数据了,等可写事件来了再重试”。它不是你手动调用的函数,也不该被业务代码感知:
-
send_wait为1时,swConnection_buffer_send会跳过发送,避免反复send失败 - Reactor 收到
EPOLLOUT事件后,会重新触发该连接的发送逻辑 - 如果你在协程中用
$client->send(),底层自动处理了等待逻辑,你完全看不到send_wait - 但如果你手写非阻塞 socket +
epoll,就得自己维护类似send_wait的状态,否则会忙等
同步发送容易卡住 reactor 线程
在 Reactor 线程(比如 swoole_server 的主循环)里,绝对不能出现真正意义上的“同步发送”:
-
swClient_tcp_send_sync这类函数只允许在独立进程/线程中使用(如 Worker 进程里起一个同步swoole_client) - 若在 Reactor 线程中强行用阻塞 socket 调
send,一旦网络卡顿或对端接收窗口满,整个事件循环就会卡住,新连接、心跳、定时器全停摆 - 协程看似“同步写法”,但
$client->send()底层仍是非阻塞 +yield,不会阻塞 reactor - 错误示范:
stream_socket_client(..., $err, $msg, 30)创建阻塞 socket 后直接fwrite,在协程环境里也会破坏调度
真正要注意的不是“选 send 还是 sendwait”,而是:你当前代码运行在哪种执行模型下(同步进程 / Reactor 线程 / 协程)、socket 是否被正确设为非阻塞、以及上层有没有帮你兜底处理 EAGAIN。这些细节一旦错位,轻则发不出数据,重则整条 reactor 线程挂死。
相关文章
- 《Disney Lorcana: Wilds Unknown》预购开启 首批《Toy Story》及皮克斯卡牌购买指南 07-29
- 车来了赶车闹钟如何设置 07-29
- 崩坏星穹铁道余晖残卷巨剑守护打法攻略 07-29
- 崩坏星穹铁道砂金角色部分背景介绍 07-29
- 崩坏3雷电芽衣什么时候上线 07-29
- 玩具熊的五夜后宫4代噩梦气球男孩Nightmare Balloon Boy介绍 07-29