解析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 连接mssql数据库 初学php笔记
Mar 01 PHP
使用PHPMYADMIN操作mysql数据库添加新用户和数据库的方法
Apr 02 PHP
PHP变量内存分配问题记录整理
Nov 27 PHP
ThinkPHP使用心得分享-上传类UploadFile的使用
May 15 PHP
ThinkPHP的模版中调用session数据的方法
Jul 01 PHP
PHP中防止SQL注入方法详解
Dec 25 PHP
PHP实现图片不变型裁剪及图片按比例裁剪的方法
Jan 14 PHP
Symfony学习十分钟入门经典教程
Feb 03 PHP
PHP使用socket发送HTTP请求的方法
Feb 14 PHP
php blowfish加密解密算法
Jul 02 PHP
php写一个函数,实现扫描并打印出自定目录下(含子目录)所有jpg文件名
May 26 PHP
laravel5.6实现数值转换
Oct 23 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连接MySQL查询结果中文显示乱码解决方法
2013/10/25 PHP
ThinkPHP函数详解之M方法和R方法
2015/09/10 PHP
php遍历替换目录下文件指定内容的方法
2016/11/10 PHP
PHP实现的日历功能示例
2018/09/01 PHP
js 覆盖和重载 函数
2009/09/25 Javascript
js下用层来实现select的title提示属性
2010/02/23 Javascript
js RuntimeObject() 获取ie里面自定义函数或者属性的集合
2010/11/23 Javascript
拥抱模块化的JavaScript
2012/03/07 Javascript
JavaScript从数组中删除指定值元素的方法
2015/03/18 Javascript
jQuery实现伸展与合拢panel的方法
2015/04/30 Javascript
javascript实现验证身份证号的有效性并提示
2015/04/30 Javascript
原生JS实现图片轮播效果
2016/12/26 Javascript
浅析 NodeJs 的几种文件路径
2017/06/07 NodeJs
JavaScript实现的简单Tab点击切换功能示例
2018/07/06 Javascript
vue中实现点击按钮滚动到页面对应位置的方法(使用c3平滑属性实现)
2019/12/29 Javascript
[03:06]3分钟带你回顾DOTA2完美盛典&完美大师赛
2017/12/06 DOTA
使用Pyinstaller的最新踩坑实战记录
2017/11/08 Python
使用django的ORM框架按月统计近一年内的数据方法
2019/07/18 Python
利用setuptools打包python程序的方法步骤
2020/01/18 Python
详解Python 最短匹配模式
2020/07/29 Python
selenium与xpath之获取指定位置的元素的实现
2021/01/26 Python
3D动画《斗罗大陆》上线当日播放过亿
2021/03/16 国漫
实例讲解使用CSS实现多边框和透明边框的方法
2015/09/08 HTML / CSS
国际礼品店:GiftsnIdeas
2018/05/03 全球购物
Sandro法国官网:法国成衣品牌
2019/08/28 全球购物
Crabtree & Evelyn欧盟:豪华洗浴、身体和护发
2021/03/09 全球购物
Sisley法国希思黎美国官方网站:享誉全球的奢华植物美容品牌
2020/06/27 全球购物
芭比波朗加拿大官方网站:Bobbi Brown Cosmetics CA
2020/11/05 全球购物
C语言笔试集
2012/07/24 面试题
会计找工作求职信范文
2013/12/09 职场文书
政府个人对照检查材料
2014/08/28 职场文书
党员群众路线自我剖析材料
2014/10/06 职场文书
学校运动会广播稿
2014/10/11 职场文书
百万英镑观后感
2015/06/09 职场文书
2016校本研修培训心得体会
2016/01/08 职场文书
Python中基础数据类型 set集合知识点总结
2021/08/02 Python