提升同时请求多个url的速度


原始的同时请求多个url,等待每个url返回结果再请求下一个,这样就浪费了时间在等待返回结果上。

失败的尝试:

  • 使用fopen打开文件流。结果为fopen这个函数已经等待了返回结果的那段时间,而不是立即返回的。
  • 使用fsockopen,但是每打开一个流就读取返回结果。结果,等待返回的这个逻辑就违背了初衷。

成功的尝试:

  • 使用fsocketopen同时打开多个文件流,发送http请求。然后再读取这些文件流的结果。

工作流程:

fsocketopen使用非阻塞模式打开多个文件流,并发送http头请求。此时服务器已经与目标建立了多个链接。并已经开始返回数据。接下来,遍历所有文件流,读取返回结果。

测试代码:

<?php
class mhttp{

	private $urls = array();

	private $streams;

	public function addUrl($url){
		$this->urls[] = $url;
	}

	public function request(){
		foreach ($this->urls as $url) {
			$url = parse_url($url);
			$fp = fsockopen($url['host'], 80);
			$headers = array();
			$headers[] = "GET {$url['path']} HTTP/1.1";
			$headers[] = 'Host: localhost';
			$headers[] = 'Connection: Close';
			$headerStr = '';
			foreach ($headers as $header) {
				$headerStr .= "{$header}rn";
			}
			fwrite($fp, "{$headerStr}rn");
			$this->streams[] = $fp;
		}
		sleep(1); //证明发送http请求头后,就马上开始返回结果了
		return $this->getResult();
	}

	private function getResult(){
		$result = array();
		foreach ($this->streams as $stream) {
			$tmp = '';
			while (!feof($stream)){
				$tmp .= fread($stream, 1024);
			}
			$result[] = substr($tmp, strpos($tmp, "rnrn") + 4);
			fclose($stream);
		}
		return $result;
	}
}

$urls[] = 'http://localhost/mhttp/1.php';
$urls[] = 'http://localhost/mhttp/2.php';
$urls[] = 'http://localhost/mhttp/3.php';
$urls[] = 'http://localhost/mhttp/4.php';
$mhttp = new mhttp();
foreach ($urls as $url){
	$mhttp->addUrl($url);
}
var_dump($mhttp->request());

1.php,2.php,3.php,4.php都是类似,只不过输出的是1,2,3,4。

<?php
sleep(1);
echo 1;

结果

array(4) {
[0] =>
string(1) “1”
[1] =>
string(1) “2”
[2] =>
string(1) “3”
[3] =>
string(1) “4”
}
[Finished in 1.1s]

总耗时是1.1s,在读取返回内容之前的那个sleep(1)如果去掉的话,也同样会是1.1s。这就证明了发送http请求头后目标服务器就已经向本地发送数据了。但,耗时为什么是1.1s呢?因为每个测试文件都sleep了1s。目标服务器在返回前需要执行这个sleep(1)。

写这篇文章是因为看到有人在研究yar,对比测试普通的多次远程请求跟yar的多次远程请求所耗时间。差距不小,所以,用原生的php也写了个简单的并发请求类。当然,这个类还相当不完善,有兴趣的自行完善吧~~~


发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注