如何使用curl正确处理断开的连接

时间:2016-03-29 13:51:41

标签: php curl

我正在使用curl_multi下载文件而不是我只能描述为“有点受阻的互联网类型”的连接。

使用CURLOPT_TIMEOUT_MS的默认值会使应用程序无限期挂起。因此,由于文件非常大(下载300kb文件大约需要20分钟),因此我将其配置为合适的值1,800,000(30分钟)。问题是,如果我在下载5分钟后失去连接,我必须等待25分钟才能释放句柄。

我解决问题的初衷是使用较小的超时,在30秒的范围内,然后检查curl_info是否有超时事件。如果超时,则使用范围标题重新启动该过程。

但是这里有一个严重的缺陷,服务器可能会将多个连接视为泛滥尝试并阻止我,或者服务器可能不支持范围标头(强制下载从第一个字节开始)。

是否有另一种检测丢失或重置连接的方法?

值得注意的是,我对curl_multi_select的调用使用了超时值,因此我无需等待curl即可运行代码。

1 个答案:

答案 0 :(得分:1)

如果您暂停使用curl_multi_select,如果任何或所有句柄在一段时间内未收到任何数据,您似乎可以使用它来关闭连接时间唯一的问题是你不知道哪个句柄没有收到任何数据

$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
        }
    }
}

这可能会奏效,但并不能让您找到对特定句柄的细粒度控制。

在我想要在发生故障之前很久就检测到超时的情况下,我处理超时的最佳方法是将CURLOPT_PROGRESSFUNCTIONCURLOPT_WRITEFUNCTION结合使用。

我不会将代码转换为多界面,但您可以根据自己的需要将其用于现有代码。

我们的想法是定义您自己的超时并跟踪句柄上次接收任何数据的时间。如果在这段时间内没有收到任何数据,那么您可以中止转移并尝试重新开始。

我在生产中使用它,数据应该每秒都进来,所以我想尽早发现超时。它适用于各种连接问题,并且测试表明它检测到的超时比cURL错误输出的速度快得多。

使用CURLOPT_WRITEFUNCTION的一个副作用是,您必须在阅读时保存数据,而不是使用CURLOPT_RETURNTRANSFER从{{1}获取数据}

curl_exec

不幸的是,它并不是非常简单,但它可以很好地完成你想做的事情。希望有所帮助。