我的VPS服务器出现以下问题。
我有一个长期运行的PHP脚本,可以将大文件发送到浏览器。它做了这样的事情:
<?php
header("Content-type: application/octet-stream");
readfile("really-big-file.zip");
exit();
?>
这基本上从服务器的文件系统中读取文件并将其发送到浏览器。我不能只使用直接链接(并让Apache提供文件),因为应用程序中存在需要应用的业务逻辑。
问题是,当此类下载正在运行时,该站点不会响应其他请求。
答案 0 :(得分:33)
您遇到的问题与您使用会话的事实有关。当脚本具有正在运行的会话时,它会锁定会话文件以防止可能损坏会话数据的并发写入。这意味着来自同一客户端的多个请求 - 使用相同的会话ID - 将不会同时执行,它们将排队并且一次只能执行一个。
多个用户不会遇到此问题,因为他们将使用不同的会话ID。这并不意味着您没有问题,因为您可能想要在下载文件时访问该站点,或者一次下载多个文件。
解决方案实际上非常简单:在开始输出文件之前调用session_write_close()
。这将关闭会话文件,释放锁并允许执行进一步的并发请求。
答案 1 :(得分:2)
您的服务器设置可能不是您应该检查的唯一地方。
尝试照常从浏览器处执行请求,然后从其他客户端执行另一项请求。
来自同一台机器的wget或另一台机器上的其他浏览器。
答案 2 :(得分:1)
服务器以何种方式响应其他请求?是“等待example.com ......”还是会出现任何错误?
我做了类似的事情,但我提供了chunked文件,这使得文件系统在客户端接受并下载一个块时会中断,这比一次提供整个文件要好,这对文件要求很高系统和整个服务器。
编辑:虽然不是这个问题的答案,但是提问者询问了阅读文件的问题。这是我使用的功能。提供文件的完整路径。function readfile_chunked($file_path, $retbytes = true)
{
$buffer = '';
$cnt = 0;
$chunksize = 1 * (1024 * 1024); // 1 = 1MB chunk size
$handle = fopen($file_path, 'rb');
if ($handle === false) {
return false;
}
while (!feof($handle)) {
$buffer = fread($handle, $chunksize);
echo $buffer;
ob_flush();
flush();
if ($retbytes) {
$cnt += strlen($buffer);
}
}
$status = fclose($handle);
if ($retbytes && $status) {
return $cnt; // return num. bytes delivered like readfile() does.
}
return $status;
}
答案 3 :(得分:0)
我尝试了不同的方法(使用PEARs HTTP_Download读取和发送小块文件[参见PHP文档中readfile
的评论])但是当文件变大时我总是遇到性能问题。< / p>
有一个Apache mod X-Sendfile
,您可以在其中执行业务逻辑,然后将下载委派给Apache。下载将不会公开。我认为,这是解决问题的最佳方案。
更多信息:
答案 4 :(得分:0)
同样的事情发生在我身上,我没有使用会话。 session.auto_start设置为0 我的示例脚本只运行“sleep(5)”,并且在开头添加“session_write_close()”并不能解决问题。
答案 5 :(得分:0)
检查您的httpd.conf文件。也许你有“KeepAlive On”,这就是为什么你的第二个请求会挂起,直到第一个请求完成。通常,您的PHP脚本不应允许访问者等待很长时间。如果您需要下载大量内容,请在用户无法直接控制的单独内部请求中执行此操作。在完成之前,将一些“执行”状态返回给最终用户,并在完成后处理实际结果。