解析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 相关文章推荐
第九节--绑定
Nov 16 PHP
PHP小程序自动提交到自助友情连接
Nov 24 PHP
认识并使用PHP超级全局变量
Jan 26 PHP
CentOS 6.2使用yum安装LAMP以及phpMyadmin详解
Jun 17 PHP
CodeIgniter启用缓存和清除缓存的方法
Jun 12 PHP
php程序总是提示验证码输入有误解决方案
Jan 07 PHP
教你在PHPStorm中配置Xdebug
Jul 27 PHP
PHP中两个float(浮点数)比较实例分析
Sep 27 PHP
PHP基于正则批量替换Img中src内容实现获取缩略图的功能示例
Jun 07 PHP
PHP实践教程之过滤、验证、转义与密码详解
Jul 24 PHP
PHP单例模式实例分析【防继承,防克隆操作】
May 22 PHP
PHP使用openssl扩展实现加解密方法示例
Feb 20 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中使用explode查找某个字符是否存在的方法
2011/07/12 PHP
php中session过期时间设置及session回收机制介绍
2014/05/05 PHP
初识php MVC
2014/09/10 PHP
Laravel实现表单提交
2017/05/07 PHP
php中加密解密DES类的简单使用方法示例
2020/03/26 PHP
jQuery 表单验证扩展代码(二)
2010/10/20 Javascript
js data日期初始化的5种方法
2013/12/29 Javascript
jquery mobile的触控点击事件会多次触发问题的解决方法
2014/05/08 Javascript
javascript对中文按照拼音排序代码
2014/08/20 Javascript
RequireJS入门一之实现第一个例子
2015/09/30 Javascript
jQuery实现的鼠标经过时变宽的效果(附demo源码)
2016/04/28 Javascript
浅谈JavaScript中面向对象的的深拷贝和浅拷贝
2016/08/01 Javascript
Bootstrap Table的使用总结
2016/10/08 Javascript
使用jquery实现的循环连续可停顿滚动实例
2016/11/23 Javascript
利用Vue实现移动端图片轮播组件的方法实例
2017/08/23 Javascript
vue中实现在外部调用methods的方法(推荐)
2018/02/08 Javascript
js html实现计算器功能
2018/11/13 Javascript
angular6开发steps步骤条组件
2019/07/04 Javascript
JavaScript实现京东放大镜效果
2019/12/03 Javascript
[04:51]TI10典藏宝瓶Ⅱ外观视频展示
2020/08/15 DOTA
在Python的Django框架中simple-todo工具的简单使用
2015/05/30 Python
Python对数据库操作
2016/03/28 Python
Python创建xml文件示例
2017/03/22 Python
Python对象与引用的介绍
2019/01/24 Python
Django如何使用asyncio协程和ThreadPoolExecutor多线程
2020/10/12 Python
Python如何批量生成和调用变量
2020/11/21 Python
美国美发品牌:Bumble and Bumble
2016/10/08 全球购物
美国最受欢迎的度假目的地优惠套餐:BookVIP
2018/09/27 全球购物
linux面试题参考答案(5)
2016/11/05 面试题
财务会计专业个人求职信范本
2014/01/08 职场文书
讲文明懂礼貌演讲稿
2014/09/11 职场文书
2014年前台文员工作总结
2014/12/08 职场文书
街道社区活动报告
2015/02/05 职场文书
大学生学年个人总结
2015/02/15 职场文书
2019奶茶店创业计划书范本!
2019/07/15 职场文书
HTML实现仿Windows桌面主题特效的实现
2022/06/28 HTML / CSS