解析php中curl_multi的应用


Posted in PHP onJuly 17, 2013

相信许多人对php手册中语焉不详的curl_multi一族的函数头疼不已,它们文档少,给的例子 更是简单的让你无从借鉴,我也曾经找了许多网页,都没见一个完整的应用例子。
•curl_multi_add_handle
•curl_multi_close
•curl_multi_exec
•curl_multi_getcontent
•curl_multi_info_read
•curl_multi_init
•curl_multi_remove_handle
•curl_multi_select
一般来说,想到要用这些函数时,目的显然应该是要同时请求多个url,而不是一个一个依次请求,否则不如自己循环去调curl_exec好了。

步骤总结如下:
第一步:调用curl_multi_init
第二步:循环调用curl_multi_add_handle
这一步需要注意的是,curl_multi_add_handle的第二个参数是由curl_init而来的子handle。
第三步:持续调用curl_multi_exec
第四步:根据需要循环调用curl_multi_getcontent获取结果
第五步:调用curl_multi_remove_handle,并为每个字handle调用curl_close
第六步:调用curl_multi_close

这里有一个网上找的简单例子,其作者称为dirty的例子,(稍后我会说明为何dirty):

*
Here's a quick and dirty example for curl-multi from PHP, tested on PHP 5.0.0RC1 CLI / FreeBSD 5.2.1
*/
$connomains = array(
"http://www.cnn.com/",
"http://www.canada.com/",
"http://www.yahoo.com/"
);
$mh = curl_multi_init();
foreach ($connomains as $i => $url) {
     $conn[$i]=curl_init($url);
      curl_setopt($conn[$i],CURLOPT_RETURNTRANSFER,1);
      curl_multi_add_handle ($mh,$conn[$i]);
}
do { $n=curl_multi_exec($mh,$active); } while ($active);
foreach ($connomains as $i => $url) {
      $res[$i]=curl_multi_getcontent($conn[$i]);
      curl_close($conn[$i]);
}
print_r($res);

整个使用过程差不多就是这样,但是,这个简单代码有个致命弱点,就是在do循环的那段,在整个url请求期间是个死循环,它会轻易导致CPU占用100%。

现在我们来改进它,这里要用到一个几乎没有任何文档的函数curl_multi_select了,虽然C的curl库对select有说明,但是,php里的接口和用法确与C中有不同。

把上面do的那段改成下面这样:

do {
                        $mrc = curl_multi_exec($mh,$active);
                } while ($mrc == CURLM_CALL_MULTI_PERFORM);
                while ($active and $mrc == CURLM_OK) {
                        if (curl_multi_select($mh) != -1) {
                                do {
                                        $mrc = curl_multi_exec($mh, $active);
                                } while ($mrc == CURLM_CALL_MULTI_PERFORM);
                        }
                }

因为$active要等全部url数据接受完毕才变成false,所以这里用到了curl_multi_exec的返回值判断是否还有数据,当有数据的时候就不停调用curl_multi_exec,暂时没有数据就进入select阶段,新数据一来就可以被唤醒继续执行。这里的好处就是CPU的无谓消耗没有了。

另外:还有一些细节的地方可能有时候要遇到:
控制每一个请求的超时时间,在curl_multi_add_handle之前通过curl_setopt去做:
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);

判断是否超时了或者其他错误,在curl_multi_getcontent之前用:curl_error($conn[$i]);

注意:php的multi_curl功能慎用,因为某些版本的curl和php的搭配有Bug。所以你调试过没问题的代码很可能在别的机器上不正确。

例如今天我发现在php5.2.2搭配curl/7.16.2版本如果CURLOPT_USERAGENT属性设置成某些值,则实际发送的HTTP头的会变成一串二进制值。

而恰好这个版本的php中strip_tags函数对含二进制的数据处理的不好,这才发现了这个Bug

PHP 相关文章推荐
如何对PHP程序中的常见漏洞进行攻击
Oct 09 PHP
php str_pad 函数使用详解
Jan 13 PHP
php url地址栏传中文乱码解决方法集合
Jun 25 PHP
PHP截断标题且兼容utf8和gb2312编码
Sep 22 PHP
PHP中使用Session配合Javascript实现文件上传进度条功能
Oct 15 PHP
php使用MySQL保存session会话的方法
Jun 18 PHP
搭建Vim为自定义的PHP开发工具的一些技巧
Dec 11 PHP
PHP实现的限制IP投票程序IP来源分析
May 04 PHP
php格式化时间戳
Dec 17 PHP
Laravel5框架添加自定义辅助函数的方法
Aug 01 PHP
laravel Task Scheduling(任务调度)在windows下的使用详解
Oct 22 PHP
PHP设计模式(六)桥连模式Bridge实例详解【结构型】
May 02 PHP
php curl获取网页内容(IPV6下超时)的解决办法
Jul 16 #PHP
ie与session丢失(新窗口cookie丢失)实测及解决方案
Jul 15 #PHP
实测在class的function中include的文件中非php的global全局环境
Jul 15 #PHP
Php output buffering缓存及程序缓存深入解析
Jul 15 #PHP
PHP 转义使用详解
Jul 15 #PHP
thinkphp 一个页面使用2次分页的实现方法
Jul 15 #PHP
shell脚本作为保证PHP脚本不挂掉的守护进程实例分享
Jul 15 #PHP
You might like
长波有什么东西
2021/03/01 无线电
php 计算两个时间戳相隔的时间的函数(小时)
2009/12/18 PHP
php数组函数序列之array_search()- 按元素值返回键名
2011/11/04 PHP
PHP实现的进度条效果详解
2016/05/03 PHP
Aster vs KG BO3 第三场2.19
2021/03/10 DOTA
修改jquery.lazyload.js实现页面延迟载入
2010/12/22 Javascript
js open() 与showModalDialog()方法使用介绍
2013/09/10 Javascript
getAsDataURL在Firefox7.0下无法预览本地图片的解决方法
2013/11/15 Javascript
JS,Jquery获取select,dropdownlist,checkbox下拉列表框的值(示例代码)
2014/01/11 Javascript
javascript跨浏览器的属性判断方法
2014/03/16 Javascript
js实现Select下拉框具有输入功能的方法
2015/02/06 Javascript
javascript 常见功能汇总
2015/06/11 Javascript
JavaScript对象数组排序函数及六个用法
2015/12/23 Javascript
JavaScript构造函数详解
2015/12/27 Javascript
基于JavaScript实现 网页切出 网站title变化代码
2016/04/03 Javascript
使用jQuery.Qrcode插件在客户端动态生成二维码并添加自定义Logo
2016/09/01 Javascript
谈谈JavaScript中super(props)的重要性
2019/02/12 Javascript
在vue中使用axios实现post方式获取二进制流下载文件(实例代码)
2019/12/16 Javascript
vue 微信扫码登录(自定义样式)
2020/01/06 Javascript
Node Express用法详解【安装、使用、路由、中间件、模板引擎等】
2020/05/13 Javascript
node.js文件的复制、创建文件夹等相关操作
2021/02/05 Javascript
[03:09]2014DOTA2国际邀请赛 Mushi前队友送上祝福
2014/07/12 DOTA
[06:45]DOTA2-DPC中国联赛 正赛 Magma vs LBZS 选手采访
2021/03/11 DOTA
Python中列表list以及list与数组array的相互转换实现方法
2017/09/22 Python
Python实现快速排序的方法详解
2019/10/25 Python
python OpenCV GrabCut使用实例解析
2019/11/11 Python
pytorch中的transforms模块实例详解
2019/12/31 Python
python如何调用字典的key
2020/05/25 Python
css3实现input输入框颜色渐变发光效果代码
2014/04/02 HTML / CSS
实例讲解利用HTML5 Canvas API操作图形旋转的方法
2016/03/22 HTML / CSS
大型演出策划方案
2014/05/28 职场文书
承诺书范文
2014/06/03 职场文书
旅游与环境专业求职信
2014/06/05 职场文书
2014年乡镇人大工作总结
2014/11/25 职场文书
拾金不昧感谢信范文
2015/01/21 职场文书
2015年仓管员工作总结
2015/04/21 职场文书