php和curl无法处理睡眠的非阻塞请求

时间:2009-10-25 17:34:15

标签: php curl

我已经设置了一个小脚本来使用curl_multi_ *代码的已知cUrl功能来提供异步非阻塞请求,这是代码的粗略版本:

$mch = curl_multi_init();
$ch = curl_init();

url_setopt($ch, CURLOPT_URL,         $url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);          

curl_multi_add_handle($mch ,$ch);
$running = null;
do {
    curl_multi_exec($mch ,$running);
} while($running > 0);

curl_multi_remove_handle($mch,$ch);
curl_close($ch);

基本上这用于发送一个请求作为并行请求,以允许代码继续运行,而另一个脚本通过cURL调用,我不关心结果,因此我没有使用代码来处理它我只想要其他在curl调用后的代码将继续运行时调用脚本。

首先,我不明白为什么我需要while循环,不会为一个请求工作调用multi_exec一次?因为不使用循环不会在$ url上运行脚本(我选中了)。

其次和我最大的问题,这应该是异步的,我尝试将sleep(10)放在另一个脚本上,并且调用脚本在继续之前等待10秒,我不明白它应该是非阻塞的并且应该继续运行。

我做错了什么?

2 个答案:

答案 0 :(得分:4)

让我们从最后开始。

当您的PHP完成运行脚本时,它会执行清理并终止所有仍在运行的curl句柄。重要的是要记住这一点。

现在,每个curl请求分为多个步骤,如初始化连接,连接,写入数据,读取数据,关闭连接。可以重复中间步骤。而且我确信实际上幕后发生了更复杂的事情,但总的来说这个描述应该是正确的。

curl_multi_exec控制多句柄中的每个句柄,并允许它执行下一步,无论它是什么。然后函数返回。

这解释了为什么没有循环就没有看到请求的原因。这是因为您的句柄尚未到达能够执行实际连接的步骤。你的PHP脚本完成运行,执行清理,进而杀死句柄,根本没有机会做任何事情。

所以,现在很明显,你需要给你机会做点什么。一遍又一遍地运行curl_multi_exec是实现它的一种方法。

这解释了为什么你遇到等待,这些多句柄并不是真正的异步,它们看起来就像它们一样。你的循环给出了运行的机会,循环将一直运行直到请求完成(在你的例子中需要10秒)。

简短摘要:您需要找到问题的另一种解决方案(即继续运行其他代码,同时执行curl):))

答案 1 :(得分:0)

这个对我有用:

function get_web_page( $url )
{
$options = array(
    CURLOPT_RETURNTRANSFER => true,     // return web page
    CURLOPT_HEADER         => false,    // don't return headers
    CURLOPT_FOLLOWLOCATION => true,     // follow redirects
    CURLOPT_ENCODING       => "",       // handle all encodings
    CURLOPT_USERAGENT      => "spider", // who am i
    CURLOPT_AUTOREFERER    => true,     // set referer on redirect
    CURLOPT_CONNECTTIMEOUT => 120,      // timeout on connect
    CURLOPT_TIMEOUT        => 120,      // timeout on response
    CURLOPT_MAXREDIRS      => 10,       // stop after 10 redirects
);

$ch      = curl_init( $url );
curl_setopt_array( $ch, $options );
$content = curl_exec( $ch );
$err     = curl_errno( $ch );
$errmsg  = curl_error( $ch );
$header  = curl_getinfo( $ch );
curl_close( $ch );

$header['errno']   = $err;
$header['errmsg']  = $errmsg;
$header['content'] = $content;
return $header;
}

作为一项功能,您可以反复调用它。 (作为异步线程)所以你需要做的就是编写一个while循环来处理接收和处理所有收到的卷发..一旦完成,你的脚本就可以完成,避免在代码问题结束时停止。

另一点......你不需要像这样格式化你的while循环..

do { ... } while (conditional)

你可以使用:

while (conditional) { ... }