解析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 相关文章推荐
dedecms中显示数字验证码的修改方法
Mar 21 PHP
PHP Zip解压 文件在线解压缩的函数代码
May 26 PHP
php笔记之:AOP的应用
Apr 24 PHP
smarty简单分页的实现方法
Oct 27 PHP
thinkphp视图模型查询提示ERR: 1146:Table 'db.pr_order_view' doesn't exist的解决方法
Oct 30 PHP
php检测apache mod_rewrite模块是否安装的方法
Mar 14 PHP
PHP5.5迭代生成器用法实例详解
Mar 16 PHP
PHP 读取大文件并显示的简单实例(推荐)
Aug 12 PHP
遍历指定目录,并存储目录内所有文件属性信息的php代码
Oct 28 PHP
php获取当前月与上个月月初及月末时间戳的方法
Dec 05 PHP
Laravel如何使用Redis共享Session
Feb 23 PHP
解决laravel session失效的问题
Oct 14 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
PHP开发中常用的三个表单验证函数使用小结
2010/03/03 PHP
php批量缩放图片的代码[ini参数控制]
2011/02/11 PHP
文件上传之SWFUpload插件(代码)
2015/07/30 PHP
WordPres对前端页面调试时的两个PHP函数使用小技巧
2015/12/22 PHP
PHP中localeconv()函数的用法
2019/03/26 PHP
Laravel框架实现简单的学生信息管理平台案例
2019/05/07 PHP
IE不出现Flash激活框的小发现的js实现方法
2007/09/07 Javascript
jquery ajaxSubmit 异步提交的简单实现
2014/02/28 Javascript
在Node.js应用中读写Redis数据库的简单方法
2015/06/30 Javascript
jQuery点击按钮弹出遮罩层且内容居中特效
2015/12/14 Javascript
jquery实现简单的全选和反选功能
2016/01/02 Javascript
node.js+express制作网页计算器
2016/01/17 Javascript
JavaScript模版引擎的基本实现方法浅析
2016/02/15 Javascript
了解VUE的render函数的使用
2017/06/08 Javascript
vue 计时器组件的实现代码
2017/09/14 Javascript
vue项目如何监听localStorage或sessionStorage的变化
2021/01/04 Vue.js
vue3中轻松实现switch功能组件的全过程
2021/01/07 Vue.js
基于wxpython开发的简单gui计算器实例
2015/05/30 Python
python判断字符串编码的简单实现方法(使用chardet)
2016/07/01 Python
详解python实现读取邮件数据并下载附件的实例
2017/08/03 Python
python爬虫使用cookie登录详解
2017/12/27 Python
Python装饰器用法实例总结
2018/02/07 Python
python Flask 装饰器顺序问题解决
2018/08/08 Python
python3.6数独问题的解决
2019/01/21 Python
浅谈python3.6的tkinter运行问题
2019/02/22 Python
Python 函数list&read&seek详解
2019/08/28 Python
Python3离线安装Requests模块问题
2019/10/13 Python
Python实现随机生成任意数量车牌号
2020/01/21 Python
matplotlib bar()实现百分比堆积柱状图
2021/02/24 Python
CSS3 倾斜的网页图片库实例教程
2009/11/14 HTML / CSS
美国珠宝店:Helzberg Diamonds
2018/10/24 全球购物
BSTN意大利:德国街头和运动文化高品质商店
2020/12/22 全球购物
学校标语大全
2014/06/19 职场文书
单位接收函格式
2015/01/30 职场文书
2015年学生会个人工作总结
2015/04/09 职场文书
奔腾年代观后感
2015/06/09 职场文书