请教一个 nginx 做下载服务器统计下载信息的问题。

2017-01-11 15:32:59 +08:00
 xuexixuexi2

需求:需要知道有人开始下载,是否下载完成。
思路:通过 php 的 fpassthru 发送实际的文件数据,并在开始前和结束后写数据库。
代码:

$db = new DownloadDB();
$db->exec("INSERT INTO tblDownloads(info) VALUES('下载开始');");
$db->close();

$filepath = '../files/file1';
@header('Content-type: application/octet-stream');
@header('Content-Disposition: attachment; filename=' . $filename);
@header('Accept-Ranges: bytes');
@header('Content-Length: ' . filesize($filepath));
@header('Cache-control: no-cache,no-store,must-revalidate');
@header('Pragma: no-cache');
@header('Expires: 0');
$file = @fopen($filepath, "rb");
@fpassthru($file);
@fclose($file);

$db = new DownloadDB();
$db->exec("INSERT INTO tblDownloads(info) VALUES('下载完成');");
$db->close();

问题:还没有下载完,就写了“下载完成”到数据库中了,甚至是和“下载开始”同时写入数据库的。
tblDownloads 表有时间字段,可以看到下载完成和下载开始是同时写入数据库的,也就是中间的 fopen-fpassthru-fclose 这些耗时为 0 。
而我的理解是 fpassthru 应该将数据全部推送给用户后才返回,是不是有缓存机制? 要怎么能按我预想的进行?
环境: Linux+nginx+fastCGI

4433 次点击
所在节点    程序员
37 条回复
lslqtz
2017-01-12 04:12:22 +08:00
我这边测试是正常的,视频在这里: http://xinchen123.oss-cn-shanghai.aliyuncs.com/o_1b67igqepga1t4g0ahkfsua.mp4

set_time_limit(0);
ob_end_flush();
flush();
@header('Content-Length:299711208');
@header('Content-Type:application/octet-stream');
@header('Content-Disposition:attachment;filename=WindowsXP_SP2.exe');
@readfile('http://speed.myzone.cn/WindowsXP_SP2.exe');
msg7086
2017-01-12 04:35:08 +08:00
挂个 inotify 在 nginx access log 上,然后写数据库?
xuexixuexi2
2017-01-12 04:40:21 +08:00
@lslqtz 可能还是和 nginx 的模块有关吧。
我又详细测了一下,改代码位置,改 header ,都和你的一样了,还是存在这个问题。
xuexixuexi2
2017-01-12 04:48:24 +08:00
@msg7086 按你说的上网搜了一下,确实是个可行的思路。
明天试试:)
lslqtz
2017-01-12 04:57:48 +08:00
@xuexixuexi2 php/nginx 问题?不清楚,手头是 win 下的,理论可行没错。
ericls
2017-01-12 07:07:07 +08:00
最简单的做法应该是利用 nginx 的 internel routing
ericls
2017-01-12 07:07:30 +08:00
@ericls *internal
aru
2017-01-12 08:23:00 +08:00
@lslqtz 你换个本地文件发送试试。
远程文件读取太耗时了,耗时就可能和客户端下载时间接近了。
lslqtz
2017-01-12 09:05:58 +08:00
@aru 楼主的描述是计费后才开始下载,说明这时已经执行完毕并输出缓冲。
而我这个是立即执行的,有缓冲也应该是远程文件下完后才输出。
aru
2017-01-12 10:17:51 +08:00
@lslqtz 不要说那么多。直接试试使用本地的大文件(不用太大,下载方需要 3-10 秒内下完即可),看看能不能记录到准确的下载耗时。我觉得用 apache 的 mod_php 是没问题的, nginx 的 fast_cgi 不行。
lslqtz
2017-01-12 23:27:02 +08:00
@aru 我试着写了写,不能计算到准确的下载耗时。
不过之前是帮楼主解决下载之前卡住的问题。
现在把代码改成了这样,问题在于如果 readfile 换成 sleep 就可以准确的统计到:
<?php
set_time_limit(0);
ignore_user_abort(1);
ob_end_flush();
flush();
$time=time();
@header('Connection:Close');
@header('Content-Length:299711208');
@header('Content-Type:application/octet-stream');
@header('Content-Disposition:attachment;filename=WindowsXP_SP2.exe');
@readfile('1.exe');
while (!connection_aborted()) {
file_put_contents('1.txt',time()-$time);
die();
}
?>
lslqtz
2017-01-12 23:30:06 +08:00
Reply 31
lslqtz 刚刚
@aru 我试着写了写,不能计算到准确的下载耗时。
不过之前是帮楼主解决下载之前卡住的问题。
现在把代码改成了这样,问题在于如果 readfile 换成 sleep 就可以准确的统计到:
<?php
set_time_limit(0);
ignore_user_abort(1);
ob_end_flush();
flush();
$time=time();
@header('Connection:Close');
@header('Content-Length:299711208');
@header('Content-Type:application/octet-stream');
@header('Content-Disposition:attachment;filename=WindowsXP_SP2.exe');
@readfile('1.exe');
while (connection_status() != 0 || connection_aborted()) {
file_put_contents('1.txt',time()-$time);
die();
}
?>
突然感觉代码写错了...
lslqtz
2017-01-12 23:32:37 +08:00
然后又想了想,改成 while (1) {}里面加 if 会好一点。。
如果在里面的 if 判断到连接被结束了,就断开连接。
Reply 32
lslqtz 1 分钟前
Reply 31
lslqtz 刚刚
@aru 我试着写了写,不能计算到准确的下载耗时。
不过之前是帮楼主解决下载之前卡住的问题。
现在把代码改成了这样,问题在于如果 readfile 换成 sleep 就可以准确的统计到:
<?php
set_time_limit(0);
ignore_user_abort(1);
ob_end_flush();
flush();
$time=time();
@header('Connection:Close');
@header('Content-Length:299711208');
@header('Content-Type:application/octet-stream');
@header('Content-Disposition:attachment;filename=WindowsXP_SP2.exe');
@readfile('1.exe');
while (1) {
if (connection_status() != 0 || connection_aborted()) {
file_put_contents('1.txt',time()-$time);
die();
}
}
?>
aru
2017-01-13 10:39:57 +08:00
@lslqtz 我感觉,尝试在发送文件的代码做下载耗时统计的做法是歪门邪道(极大降低了 php 的性能)。
js 或者 access log 或者 nginx module 才是正确的做法。
lslqtz
2017-01-13 13:14:50 +08:00
@aru 是的,很费资源。
但我还是去实现了他 xD 。
xuexixuexi2
2017-01-13 19:46:04 +08:00
@aru 我本来专业不是做这个的, nginx 用得更少。
有没有现成的 nginx 模块可以实现这个?还有 nginx 模块是不是只能编译进 nginx 里才能用?
我看 nginx 的配置没有像 apache 的配置一样设置模块。
aru
2017-01-13 21:52:46 +08:00
@xuexixuexi2 似乎没有现成的。日志里面可以记录下载的大小和下载耗时,将这个弄成单独的一个日志文件,然后弄个脚本去做定时处理吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/333885

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX