使用PECL HTTP类在PHP中并行HTTP请求[答案:HttpRequestPool类]

时间:2008-10-03 21:18:08

标签: php http parallel-processing pecl simultaneous


HttpRequestPool类提供了解决方案。非常感谢那些指出这一点的人。

可在以下网址找到简要教程:http://www.phptutorial.info/?HttpRequestPool-construct


问题

我想在PHP中进行并发/并行/同步HTTP请求。我想避免连续请求:

  • 一组请求需要很长时间才能完成;
  • 越多,请求越多
  • 一个请求中途的一个请求的超时可能导致以后的请求不被发出(如果脚本有执行时间限制)

我设法找到制作simultaneuos [sic] HTTP requests in PHP with cURL的详细信息,但是如果可能的话,我想明确使用PHP的HTTP functions

具体来说,我需要将数据同时发送到一组URL。发布数据的网址超出了我的控制范围;它们是用户设置的。

我不介意在处理回复之前是否需要等待所有请求完成。如果我在每个请求上设置30秒的超时并同时发出请求,我知道我必须等待最多30秒(可能多一点)才能完成所有请求。

我找不到如何实现这一目标的细节。但是,我最近注意到在PHP手册中提到PHP5 +能够处理并发HTTP请求 - 我打算在当时记下它,忘记了,再也找不到了。

单个请求示例(正常工作)

<?php
$request_1 = new HttpRequest($url_1, HTTP_METH_POST);
$request_1->setRawPostData($dataSet_1);
$request_1->send();
?>

并发请求示例(不完整,清楚)

<?php
$request_1 = new HttpRequest($url_1, HTTP_METH_POST);
$request_1->setRawPostData($dataSet_1);

$request_2 = new HttpRequest($url_2, HTTP_METH_POST);
$request_2->setRawPostData($dataSet_2);

// ...

$request_N = new HttpRequest($url_N, HTTP_METH_POST);
$request_N->setRawPostData($dataSet_N);

// Do something to send() all requests at the same time
?>

任何想法都会非常感激!

澄清1 :我想坚持PECL HTTP功能:

  • 他们提供了一个很好的OOP界面
  • 它们在相关应用程序中被广泛使用,并且从维护的角度来看,坚持使用已经使用的应该是有益的
  • 与使用cURL相比,我通常必须使用PECL HTTP函数编写更少的代码行来发出HTTP请求 - 从维护的角度来看,更少的代码行也应该是有益的

澄清2 :我意识到PHP的HTTP功能没有内置,也许我在那里措辞错误,我会纠正。我不担心人们不得不安装额外的东西 - 这不是一个要分发的应用程序,它是一个带有服务器的Web应用程序。

澄清3 :如果某人权威地声明PECL HTTP无法做到这一点,我会非常高兴。

6 个答案:

答案 0 :(得分:10)

我很确定HttpRequestPool正是您所寻找的。

为了详细说明,您可以使用分叉来实现您正在寻找的东西,但这似乎不必要地复杂并且在HTML上下文中不是很有用。虽然我没有测试过,但这段代码应该是它:

// let $requests be an array of requests to send
$pool = new HttpRequestPool();
foreach ($requests as $request) {
  $pool->attach($request);
}
$pool->send();
foreach ($pool as $request) {
  // do stuff
}

答案 1 :(得分:2)

你试过HttpRequestPool(这是Http的一部分)吗?看起来它会汇集请求对象并进行处理。我知道我读过Http支持同时请求的地方除了 pool 之外我也找不到任何东西。

答案 2 :(得分:2)

我曾经不得不解决类似的问题:在不累积响应时间的情况下执行多个请求。

该解决方案最终成为使用非阻塞sockets的自定义构建函数。 它的工作原理如下:

$request_list = array(
  # address => http request string
  #
   '127.0.0.1' => "HTTP/1.1  GET /index.html\nServer: website.com\n\n",
   '192.169.2.3' => "HTTP/1.1 POST /form.dat\nForm-data: ...",
  );

foreach($request_list as $addr => $http_request) {
    # first, create a socket and fire request to every host
    $socklist[$addr] = socket_create();
    socket_set_nonblock($socklist[$addr]); # Make operation asynchronious

    if (! socket_connect($socklist[$addr], $addr, 80))
        trigger_error("Cannot connect to remote address");

    # the http header is send to this host
    socket_send($socklist[$addr], $http_request, strlen($http_request), MSG_EOF);
}

$results = array();

foreach(array_keys($socklist) as $host_ip) {
    # Now loop and read every socket until it is exhausted
    $str = socket_read($socklist[$host_ip], 512, PHP_NORMAL_READ);
    if ($str != "") 
        # add to previous string
        $result[$host_ip] .= $str;
    else
        # Done reading this socket, close it
        socket_close($socklist[$host_ip]);
}
# $results now contains an array with the full response (including http-headers)
# of every connected host.

由于thunked响应以半并行方式获取,所以速度要快得多,因为socket_read不会等待响应,但如果套接字缓冲区尚未满,则会返回。

您可以将其包装在适当的OOP界面中。您需要自己创建HTTP请求字符串,并且当然要处理服务器响应。

答案 3 :(得分:1)

一位朋友最近向我指出了CurlObjects(http://trac.curlobjects.com/trac),我觉得这对使用curl_multi非常有用。

$curlbase = new CurlBase; $curlbase->defaultOptions[ CURLOPT_TIMEOUT ] = 30; $curlbase->add( new HttpPost($url, array('name'=> 'value', 'a' => 'b'))); $curlbase->add( new HttpPost($url2, array('name'=> 'value', 'a' => 'b'))); $curlbase->add( new HttpPost($url3, array('name'=> 'value', 'a' => 'b'))); $curlbase->perform();

foreach($curlbase->requests as $request) { ... }

答案 4 :(得分:0)

PHP的HTTP函数aren't built in,它们都是PECL扩展。如果你担心的是人们不得不安装额外的东西,那么这两个解决方案都会遇到同样的问题 - 而且我认为cURL更有可能被安装,因为它默认为我曾经使用的每个网络主机。

答案 5 :(得分:-1)

您可以使用pcntl_fork()为每个请求创建一个单独的进程,然后等待它们结束:

http://www.php.net/manual/en/function.pcntl-fork.php

你有什么理由不想使用cURL吗? curl_multi_ *函数可以同时允许多个请求。