Wenn Sie curl_multi_select
mit einem Timeout verwenden, scheint es, dass Sie in der Lage sein sollten, die Verbindung zu schließen, wenn einige oder alle Handles für einen bestimmten Zeitraum keine Daten erhalten haben. Das einzige Problem ist, dass Sie nicht wissen, welcher Griff hat keine Daten
erhalten
$timeout = 45; // abort after 45 seconds with no data
$lastReceived = 0; // time data was last received
while ($active && $mrc == CURLM_OK) {
if (curl_multi_select($mh) != -1) {
do {
$mrc = curl_multi_exec($mh, $active);
$lastReceived = time();
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
} else {
if (time() - $lastReceived > $timeout) {
// no data received within timeout
// close cURL handles & multi connection and restart
}
}
}
, die funktionieren könnten, aber nicht geben Sie körnige Kontrolle über bestimmte Griffe finden.
Der beste Weg, mit Timeouts in einer Situation zu arbeiten, in der ich sie erkennen möchte, lange bevor ein Fehler auftritt, ist CURLOPT_PROGRESSFUNCTION
in Verbindung mit CURLOPT_WRITEFUNCTION
.
Ich werde den Code nicht in die Multi-Schnittstelle konvertieren, aber Sie können es in Ihren vorhandenen Code basierend auf Ihren Bedürfnissen arbeiten.
Die Idee ist, Ihr eigenes Timeout zu definieren und zu verfolgen, wann das Handle zuletzt Daten erhalten hat. Wenn in diesem Zeitraum keine Daten empfangen wurden, können Sie die Übertragung abbrechen und erneut beginnen.
Ich verwende dies in der Produktion, wo Daten in jeder Sekunde kommen sollten, so dass ich Timeouts früh erkennen möchte. Es funktioniert sehr gut für alle Arten von Verbindungsproblemen und Tests zeigten, dass es die Timeouts viel schneller erkannt hat, als es für cURL nötig gewesen wäre, um Fehler zu vermeiden.
Ein Nebeneffekt von CURLOPT_WRITEFUNCTION
verwendet wird, ist, dass Sie die Daten speichern müssen, werden, wie es gelesen hat und nicht verwenden CURLOPT_RETURNTRANSFER
die Daten von curl_exec
<?php
$readTimeout = 45; // number of seconds to time out after if no data received
$lastReceived = 0; // time data was last received on the handle
$buffer = ''; // buffer for storing response (you'll need one for each handle)
//...when initializing cURL
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'progressFunction');
curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'writeFunction');
// don't set anything for CURLOPT_RETURNTRANSFER
$result = curl_exec($ch);
$info = curl_getinfo($ch);
$error = curl_errno($ch);
// $result will be false on any failure or timeout
// check $info['http_code'] for HTTP response status
// $error will be empty if no error occurred
// on success, $buffer will contain the full response body
// if failed, you can try reconnecting and resending the request until successful
//...
function writeFunction($handle, $data)
{
global $lastReceived, $buffer; // <-- I use class properties instead
$lastReceived = time();
$size = strlen($data);
$buffer .= $data;
return $size;
}
function progressFunction($ch, $dltotal, $dlnow, $ultotal, $ulnow)
{
global $lastReceived, $readTimeout;
$time = time();
if ($time - $lastReceived > $readTimeout) {
// set error state - no data received within timeout
return 1; // non-zero causes cURL to disconnect
}
return 0;
}
zu bekommen leider Es ist nicht sehr einfach, aber es funktioniert gut zu tun, was du machen willst. Ich hoffe, das hilft.
Das größte Problem, das ich mit dem Timeout habe, ist, dass es die Verbindung beendet. Ihre vorgeschlagene Methode, die Downloadgröße innerhalb von Zeitbereichen zu verfolgen, funktioniert einwandfrei. Danke, dass Sie sich die Zeit genommen haben, eine detaillierte Antwort zu schreiben. – Twifty
Gern geschehen, hoffe es hilft.Mein Anwendungsfall war ziemlich spezifisch und ich hatte anderen Code sowohl in der progressFunction als auch in writeFunction, um andere Dinge zu tun, die ich für das Beispiel entfernt habe. Um zu erweitern, lebt die Verbindungs-/Anforderungslogik in einer Endlosschleife, die im Grunde für immer läuft und sich nach einem Timeout/Fehler wieder verbindet (entweder von progressFunction oder natürlich von cURL). – drew010