在PHP中,我基本上有以下几点:
set_time_limit(0); foreach ($files_to_send as $file) { $filesize = filesize($file); $blocksize = 1024 * 1024; // 1MB $outputted = 0; // how many bytes already sent $fid = fopen($file, 'r'); while ($outputted < $filesize) { echo fread($fid, $blocksize); $outputted += $blocksize; } }
这很好。 这是一个非常慢的服务器(英特尔凌动双核CPU),但从本地运行wget约20-24MB /秒。 从外部下载基本上填充服务器的上传速度或客户端的下载速度,以较慢者为准。 如预期的那样,500MB的下载需要大约8分钟的10mbps连接。
来自美国的人(服务器在荷兰阿姆斯特丹附近)提到,对他来说下载大约半分钟后就下载了。 他的下载速度大约是100-200KB / s,并且先不下滑。
我正在尝试诊断问题。 我已经检查了Apache的内存使用情况,并且非常稳定,这意味着PHP的输出( echo fread(...); )会阻塞,直到Apache的缓冲区已经足够空。 如果不是,PHP将继续推出字节,服务器的RAM(或至lessApache的输出缓冲区)将运行完整。 但事实并非如此。
我也检查了Apache的error.log和PHP的php_error.log任何错误。 在其他脚本中,过去几天里出现了一堆错误,这是预期的,并且确认日志正在使用中。 如果Apache或PHP会给出任何错误,那就在那里。 它不在那里。
接下来,我试图限制客户端的连接速度。 我也许应该增加延迟来更准确地模拟条件,但是我的第一个尝试只是使用wget --limit-rate=100k来限制用户报告速度的速度。 这使得下载切断,虽然wget自动重试(和工作得很好,它可以恢复文件,但我猜浏览器不会这样做)。
在Wireshark看来,缓慢下载切断的原因并不明显。 有一堆TCP窗口完整和TCP窗口更新数据包四处走动,但没有任何迹象表明,服务器可能会“是啊,不用pipe这个缓慢的连接,我有更好的事情要做”。 服务器只是在某个时间点发送一个FIN(FIN,PSH,ACK,其中包含数据,准确而言),客户端在几秒钟之后响应FIN和ACK。 几秒钟的延迟可能是由于TCP窗口已满(因为wget只消耗stream缓慢),wget还没有读取服务器的FIN数据包。
有趣的是,这个问题不会通过https发生。 它只发生在纯朴的http。
在这一点上有一些不确定性和问题:
这个TCP窗口事情是在美国的客户端发生的,还是有另一个问题呢?
我不太了解TCP窗口(我对它的作用有一个模糊的概念,并且知道这个叫做窗口缩放的东西存在,但就是这样),但连接似乎正常:服务器发送数据,客户端窗口运行已满,客户端稍后再发送数据,服务器再次发送数据等等。然后服务器就会“OK,就是这样,这是最后一个数据包FIN。
谁决定发送FIN,Apache或Windows(这是一个Windows服务器)? 如果Apache,为什么不logging它过早地结束连接?
我不知道如何继续解决这个TCP问题,所以在我花一天时间研究和testing之前,我想知道我正在寻找正确的问题。 但如何弄清楚这是否是正确的问题呢? 我不能要求客户下载,安装和使用Wireshark。 (在服务器上运行数据包捕获非常耗费CPU资源,在捕获过程中我不得不协调下载,所以这是最后的select。)
有没有人有这样的问题的经验:要么PHP + Apache切断下载,或TCP连接被终止奇怪只有在HTTP(不是https)?
或者有没有人有想法如何排除故障?
服务器使用Apache 2.4.17和PHP 5.4.25运行Windows 7(32位)。 服务器有一个50 / 50mbps的线路,在NAT后面,但configuration了端口转发。 客户端使用Windows 8 64位和Google Chrome浏览器。 如果需要,我可以提供一个客户端捕获的PCAP(15MB)的问题,给一个URL,以便您可以自己testing,并链接到PHP代码的Github存储库。