workerman 无法直接控制 tcp 滑动窗口大小,该参数由 linux 内核决定;需通过 net.ipv4.tcp_rmem、tcp_wmem 和 tcp_window_scaling 等内核参数系统级调优,workerman 仅能间接影响窗口利用率。

Workerman 本身不直接控制 TCP 滑动窗口大小——那是 Linux 内核协议栈的事。你调 TcpConnection 或改 $connection->keepConnection,都不会影响 tcp_rmem、tcp_wmem 或窗口缩放(Window Scaling)开关。想靠 Workerman “设置滑动窗口”,属于方向性误解。
滑动窗口大小由内核参数决定,不是 PHP 层能改的
Linux 中 TCP 接收/发送窗口的实际大小,取决于以下三个内核参数:
-
net.ipv4.tcp_rmem:三元组,格式为"min default max",单位字节,控制接收缓冲区上下限 -
net.ipv4.tcp_wmem:同上,控制发送缓冲区 -
net.ipv4.tcp_window_scaling:布尔值,决定是否启用窗口缩放(必须为1才能让窗口突破 64KB 上限)
这些参数在连接建立前就已生效,Workerman 启动时根本没机会干预。PHP 层连 setsockopt(SO_RCVBUF) 都极少主动调用(Workerman 底层用的是 libevent/libuv,也不暴露该接口),更别说动态调窗口了。
Workerman 能做的间接优化只有这几点
虽然不能改窗口,但 Workerman 的行为会影响窗口利用率:
- 确保开启长连接:
$connection->keepConnection = true,避免反复建连导致窗口从初始值(通常 64KB)重新起步 - 避免应用层处理过慢:如果
onMessage里做阻塞文件读写或密集计算,接收缓冲区会被填满,接收方会通告小窗口甚至 0 窗口,触发“窗口探测”(window probe),拖慢传输 - 禁用 Nagle 算法(可选):对小包敏感场景有用,但大文件传输中影响极小;Workerman 默认未启用
TCP_NODELAY,如需开启,得自己用stream_set_option($connection->getSocket(), STREAM_CONTEXT_SET_OPTION, ...)注入,但不推荐盲目开 - 确认底层事件循环支持高吞吐:比如用
Worker::$eventLoopClass = 'Workerman\Lib\Select';就比默认的Select更差;优先选Event或Ev
真正有效的调优必须落在系统层
如果你在传 GB 级文件且速度卡在 10MB/s 上不去,大概率是 BDP(带宽延迟积)没匹配上窗口上限。这时候要做的不是改 PHP 代码,而是:
- 查当前窗口能力:
ss -i看某个连接的rcv_space和wscale是否为7(表示启用缩放) - 算 BDP:假设带宽 1Gbps、RTT 30ms → BDP ≈ (1e9 / 8) * 0.03 ≈ 3.75MB,那
tcp_rmem的max至少设到 4MB 以上 - 临时生效:
sudo sysctl -w net.ipv4.tcp_rmem="4096 262144 4194304" - 永久生效:写入
/etc/sysctl.conf并sysctl -p - 别忘了同步调
tcp_wmem和打开tcp_window_scaling=1
Workerman 进程启动后,所有新 TCP 连接都会继承这些内核设置——这才是真正起效的地方。
很多人卡在“以为改了 Workerman 就等于调了 TCP”,结果调了一堆 onMessage 逻辑,网络层瓶颈纹丝不动。窗口缩放不是开关按钮,是整条链路的协同:内核参数、网卡驱动、中间设备(尤其老防火墙会 strip TCP options)、甚至远端是否支持 wscale——漏掉任意一环,tcp_window_scaling=1 都白设。











