解析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 解决旧系统 查出所有数据分页的类
Aug 27 PHP
PHP中读取文件的8种方法和代码实例
Aug 05 PHP
ThinkPHP中自定义目录结构的设置方法
Aug 15 PHP
微信公众平台开发关注及取消关注事件的方法
Dec 23 PHP
四种php中webservice实现的简单架构方法及实例
Feb 03 PHP
joomla组件开发入门教程
May 04 PHP
PHP数组函数知识汇总
May 12 PHP
golang与php实现计算两个经纬度之间距离的方法
Jul 22 PHP
php array_pop 删除数组最后一个元素实例
Nov 02 PHP
分析php://output和php://stdout的区别
May 06 PHP
Laravel利用gulp如何构建前端资源详解
Jun 03 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中常用的字符串格式化函数总结
2014/11/19 PHP
CentOS下与Apache连接的PHP多版本共存方案实现详解
2015/12/19 PHP
PHP+mysql实现的三级联动菜单功能示例
2019/02/15 PHP
ThinkPHP框架结合Ajax实现用户名校验功能示例
2019/07/03 PHP
javascript学习笔记(七)利用javascript来创建和存储cookie
2011/04/08 Javascript
Jquery 点击按钮显示和隐藏层的代码
2011/07/25 Javascript
JS实现图片横向滚动效果示例代码
2013/09/04 Javascript
jQuery插件开发精品教程让你的jQuery提升一个台阶
2016/01/27 Javascript
老生常谈javascript变量的命名规范和注释
2016/09/29 Javascript
原生JS实现导航下拉菜单效果
2020/11/25 Javascript
详解jquery插件jquery.viewport.js学习使用方法
2017/09/08 jQuery
vue项目中使用lib-flexible解决移动端适配的问题解决
2018/08/23 Javascript
微信小程序在地图选择地址并返回经纬度简单示例
2018/12/03 Javascript
angularjs http与后台交互的实现示例
2018/12/21 Javascript
qrcode生成二维码微信长按无法识别问题的解决
2019/04/04 Javascript
优雅的处理vue项目异常实战记录
2019/06/05 Javascript
小程序实现左滑删除效果
2019/07/25 Javascript
JS页面动态绘图工具SVG,Canvas,VML介简介
2020/10/16 Javascript
小程序角标的添加及绑定购物车数量进行实时更新的实现代码
2020/12/07 Javascript
[56:18]VGJ.S vs Secret 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
Python使用Beautiful Soup包编写爬虫时的一些关键点
2016/01/20 Python
Python实现的密码强度检测器示例
2017/08/23 Python
Python简单实现两个任意字符串乘积的方法示例
2018/04/12 Python
对Python之gzip文件读写的方法详解
2019/02/08 Python
Pyinstaller打包Scrapy项目的实现步骤
2020/09/22 Python
HTML5全屏(Fullscreen)API详细介绍
2015/04/24 HTML / CSS
智利最大的网上商店:Linio智利
2016/11/24 全球购物
trivago美国:全球最大的酒店价格比较网站
2018/01/18 全球购物
顶丰TOPPIK台湾官网:增发纤维假发,告别秃发困扰
2018/06/13 全球购物
英国派对礼服和连衣裙购物网站:TFNC London
2018/07/07 全球购物
麦当劳印度网上订餐:McDelivery
2020/03/16 全球购物
欢送退休感言
2014/02/08 职场文书
面试自我介绍演讲稿
2014/04/29 职场文书
贷款担保书
2015/01/20 职场文书
南京大屠杀观后感
2015/06/02 职场文书
nginx对http请求处理的各个阶段详析
2021/03/31 Servers