使用PHP ping数千个网站的最快方法

时间:2010-12-09 19:15:10

标签: php performance

我目前正在使用CURL + PHP ping URL。但是在我的脚本中,发送了一个请求,然后它等待响应,然后是另一个请求,......如果每个响应需要大约3秒,为了ping 10k链接需要8个多小时!

有没有办法一次发送多个请求,比如某种多线程?

谢谢。

9 个答案:

答案 0 :(得分:3)

答案 1 :(得分:3)

使用curl中可用的curl_multi_*函数。见http://www.php.net/manual/en/ref.curl.php

您必须将网址分组为较小的集合:一次添加所有10k链接的可能性不大。因此,围绕以下代码创建一个循环,并在$urls变量中使用URLS的子集(如100)。

$all = array();
$handle = curl_multi_init();
foreach ($urls as $url) {
    $all[$url] = curl_init();
    // Set curl options for $all[$url]
    curl_multi_add_handle($handle, $all[$url]);
}
$running = 0;
do {
    curl_multi_exec($handle, $running;);
} while ($running > 0);
foreach ($all as $url => $curl) {
    $content = curl_multi_getcontent($curl);
    // do something with $content
    curl_multi_remove_handle($handle, $curl);
}
curl_multi_close($handle);

答案 2 :(得分:3)

首先,我想指出,这不是您可以在任何类型的共享托管服务提供商上执行的基本任务。我猜你肯定会被禁止。

所以我假设您能够编译软件(VPS?)并在后台启动长时间运行的进程(使用php cli)。我会使用redis(我非常喜欢predis作为PHP客户端库)来列出列表中的push消息。 ( PS:我更愿意在node.js / python中编写这个(下面的解释适用于PHP),因为我认为这个任务可以用这些语言编写得非常快。我将尝试编写并发布github上的代码。

<强> Redis的:

  

Redis是一个高级键值存储。   它类似于memcached但是   数据集不是易失性的,也不是值   可以是字符串,完全像   memcached,但也列出,设置和   有序集。所有这些数据类型都可以   用原子操作来操纵   推送/弹出元素,添加/删除   元素,执行服务器端联合,   交集,集之间的差异,   等等。 Redis支持不同的   一种分类能力。

然后启动一些工作进程,这些进程将从列表中take(阻止,如果没有可用的话)消息。

<强> BLPOP:

  

这是Redis真正得到的地方   有趣。 BLPOP和BRPOP是   阻止LPOP的等价物   RPOP命令。如果队列为任何一个   他们指定的键有一个项目   它,该项目将被弹出   回。如果没有,Redis   客户端将阻塞,直到密钥成为   可用(或超时到期 -   为无限超时指定0。)

Curl并不完全是ping(ICMP Echo),但我想有些服务器可以阻止这些请求(安全性)。我首先尝试ping(使用nmap代码段部分)主机,如果ping失败则返回卷曲,因为ping比使用curl更快。

<强>的libcurl:

  

免费的客户端网址转移   库,支持FTP,FTPS,Gopher   (协议),HTTP,HTTPS,SCP,SFTP,   TFTP,TELNET,DICT,FILE,LDAP,LDAPS,   IMAP,POP3,SMTP和RTSP(最后一个   四个版本比版本更新   2010年2月7日或2010年2月9日)

<强>平:

  

Ping是一个计算机网络   用于测试的管理实用程序   一个主机的可达性   互联网协议(IP)网络和   衡量往返时间   从始发者发送的消息   托管到目标计算机。该   名字来自主动声纳   术语。 Ping通过发送操作   Internet控制消息协议   (ICMP)echo请求包到   目标主机并等待ICMP   响应。

但是你应该做一个HEAD请求,只检索标头以检查主机是否已启动。否则你也会下载url的内容(需要时间/成本带宽)。

<强> HEAD

  

HEAD方法与GET相同   除了服务器不能返回   响应中的消息正文。该   HTTP中包含的元信息   响应HEAD请求的标头   应该与信息完全相同   发送以响应GET请求。   该方法可用于获得   关于实体的元信息   没有提出要求所暗示的   转移实体 - 身体本身。   此方法通常用于测试   有效性的超文本链接,   可访问性,最近   修改

然后每个工作进程都应该使用curl_multi。我认为this链接可能提供了一个很好的实现(减去它不做头请求)。在每个进程中都有某种并发性。

答案 3 :(得分:1)

PHP没有真正的多线程功能。

但是,您始终可以异步进行CURL请求。

这将允许您一次发射批量的ping而不是一次。

参考:How do I make an asynchronous GET request in PHP?

编辑:请记住,你必须让你的PHP等到所有回复都在终止之前回来。

  • 基督教

答案 4 :(得分:1)

curl具有“多请求”功能,这实际上是一种执行线程请求的方式。研究此页面上的示例:http://www.php.net/manual/en/function.curl-multi-exec.php

答案 5 :(得分:0)

我会使用system()并将ping脚本作为新进程执行。或多个过程。

您可以创建一个包含所有地址的集中队列来ping,然后在该任务上启动一些ping脚本。

请注意:

  

如果程序以此启动   功能,以便继续   在后台运行,输出   该程序必须重定向到一个   文件或其他输出流。失败   这样做会导致PHP挂起,直到   程序的执行结束。

答案 6 :(得分:0)

您可以使用PHP exec()函数执行像wget这样的unix命令来完成此操作。

exec('wget -O - http://example.com/url/to_ping /dev/null 2>&1 &');

它绝不是一个理想的解决方案,但确实完成了工作,并通过将输出发送到/ dev / null并在后台运行它,您可以转到下一个“ping”而无需等待响应。 / p>

注意:出于安全考虑,某些服务器已禁用exec()。

答案 7 :(得分:0)

要处理此类任务,请尝试I / O多路复用策略。简而言之,我的想法是你创建了一堆套接字,将它们提供给你的操作系统(比如在FreeBSD上使用linux上的 epoll / kqueue )然后睡觉直到某些套接字上发生了事件。您的操作系统内核可以在单个进程中并行处理数百甚至数千个套接字。

您不仅可以处理TCP套接字,还可以以类似的方式并行处理定时器/文件描述符。

回到PHP,查看类似https://github.com/reactphp/event-loop的内容,它会公开一个好的API并隐藏许多低级细节。

答案 8 :(得分:-1)

运行多个php进程。

流程1:ping网站1-1000

流程2:ping网站1001-2001

...