
Notiz:Administratoren, bitte stimmen Sie für die Migration zu ServerFault.
Ich verwende ein LAMP-Setup mit PHP mod_fcgid
. Bei den meisten Anfragen funktioniert das gut, aber ich habe festgestellt, dass, wenn ich eine Datei herunterlade, den Download aber unterbreche, bevor er abgeschlossen ist, der PHP-CGI-Prozess, der die Datei bedient, den Versuch blockiert, weitere Daten zu schreiben, bis das IPCCommTimeout
Timeout erreicht ist. Sobald das Timeout erreicht ist, wird der Prozess unterbrochen und beginnt wieder mit der Bearbeitung anderer Anfragen.
Gibt es eine Einstellung für fcgid, die ich so einrichten kann, dass es abgebrochen wird, wenn die Ausgabe nicht erfasst wird? Kann ich in PHP etwas tun, um damit umzugehen?
Das Problem tritt nicht auf, wenn der Download nicht unterbrochen wird. Tatsächlich ist es mir nur aufgefallen, weil ich versucht habe, eine FLV-Datei mit gddflvplayer zu streamen. Dieser scheint eine kurze Anfrage zu senden, um die ersten paar Frames abzurufen, und dann eine weitere, um sie abzuspielen, was dasselbe Problem verursacht.
Zu Ihrer Information, dies ist die Strace des hängenden CGI-Prozesses; er bleibt so, bis er schließlich unterbrochen wird, vermutlich vom Prozessmanager, wenn IPCCommTimeout
erreicht wird. Ich vermute, dass er beim Versuch, die Ergebnisse des readfile()
Aufrufs auszugeben, hängen bleibt, aber Apache hört nicht mehr zu (da die Anforderung vom Benutzer abgebrochen wurde).
root@some-machine:~# strace -p 24837
Process 24837 attached - interrupt to quit
write(3, "\5|A\313%\35\337\376\275\237\230\266\242\371\37YjzD<\322\215\357\336:M\362P\335\242\214\341"..., 17432
Die Protokolle zeigen, dass die Anfrage aufgrund des Timeouts letztendlich abgelehnt wird.
mod_fcgid: read data timeout in 240 seconds
Der Download-Code dient mehr oder weniger nur readfile
zum Bereitstellen der Datei, wobei auch einige Header beteiligt sind (Hinweis: In diesem Code Header
handelt es sich mehr oder weniger nur um einen Wrapper, header()
um Probleme bei Tests zu vermeiden).
$filepath = '/some/path/foo.flv';
$filename = 'foo.flv';
$disposition = 'inline';
$h = Header::get();
$h->send('Pragma: public');
$h->send('Content-Transfer-Encoding: binary');
$h->send('Content-type: ' . FileSystem::get()->getMimeType($filepath));
$h->send('Content-Length: ' . FileSystem::get()->getFileSize($filepath));
$h->send('Content-Disposition: ' . $disposition . '; filename="' . $filename . '"');
$h->send('Content-transfer-encoding: 8bit');
$h->send('Expires: 0');
$h->send('Pragma: cache');
$h->send('Cache-Control: private');
flush();
readfile($filepath);