Параллельные HTTP-запросы в PHP с использованием HTTP-классов PECL [Ответ: класс HttpRequestPool] - PullRequest
11 голосов
/ 04 октября 2008
<ч />

Класс HttpRequestPool предоставляет решение. Большое спасибо тем, кто указал на это.

Краткое руководство можно найти по адресу: http://www.phptutorial.info/?HttpRequestPool-construct

<ч />

Задача

Я бы хотел сделать параллельные / параллельные / одновременные HTTP-запросы в PHP. Я хотел бы избежать последовательных запросов как:

  • набор запросов займет слишком много времени; чем больше запросов, тем дольше
  • тайм-аут одного запроса в середине набора может привести к тому, что последующие запросы не будут выполнены (если у скрипта есть ограничение по времени выполнения)

Мне удалось найти детали для одновременного выполнения HTTP-запросов в PHP с помощью cURL , однако я бы хотел явно использовать PHP HTTP-функции , если это вообще возможно.

В частности, мне нужно одновременно отправлять данные в набор URL-адресов. 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 как:

  • они предлагают хороший интерфейс ООП
  • они широко используются в рассматриваемом приложении, и придерживаться того, что уже используется, должно быть выгодно с точки зрения обслуживания
  • Как правило, мне нужно написать меньше строк кода для выполнения HTTP-запроса с использованием функций PECL HTTP по сравнению с использованием cURL - меньшее количество строк кода также должно быть полезным с точки зрения обслуживания

Разъяснение 2 : Я понимаю, что HTTP-функции PHP не встроены, и, возможно, я неправильно сформулировал их, что я исправлю. Я не беспокоюсь о том, что людям нужно устанавливать дополнительные компоненты - это не приложение, которое должно распространяться, а веб-приложение с самим сервером.

Разъяснение 3 : Я был бы совершенно счастлив, если бы кто-то авторитетно заявил, что HTTP PECL не может сделать это.

Ответы [ 6 ]

10 голосов
/ 13 октября 2008

Я почти уверен, 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
}
2 голосов
/ 12 октября 2008

Мне когда-то приходилось решать аналогичную проблему: делать несколько запросов без накопления времени ответа.

Решением стало создание пользовательской функции, которая использовала неблокирующие сокеты . Это работает примерно так:

$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.

Это намного быстрее, поскольку групповые ответы выбираются полупараллельно, поскольку socket_read не ожидает ответа, а возвращает, если буфер сокетов еще не заполнен.

Вы можете обернуть это в соответствующие интерфейсы ООП. Вам будет необходимо самостоятельно создать строку HTTP-запроса и, конечно, обработать ответ сервера.

2 голосов
/ 10 октября 2008

Вы пробовали HttpRequestPool (это часть Http)? Похоже, это объединит объекты запроса и обработает их. Я знаю, что где-то читал, что Http будет поддерживать одновременные запросы и кроме pool Я тоже ничего не могу найти.

1 голос
/ 09 февраля 2009

Недавно мой друг указал мне на 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();</p> <p>foreach($curlbase->requests as $request) { ... }

0 голосов
/ 04 октября 2008

PHP-функции HTTP тоже не встроены в - это расширение PECL. Если вас беспокоит необходимость установки дополнительных компонентов, у обоих решений будет одна и та же проблема - и, скорее всего, будет установлен cURL, поскольку он устанавливается по умолчанию на каждом веб-хосте, на котором я когда-либо работал.

0 голосов
/ 04 октября 2008

Вы можете использовать pcntl_fork () для создания отдельного процесса для каждого запроса, а затем дождаться их завершения:

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

Есть ли причина, по которой вы не хотите использовать cURL? Функции curl_multi_ * допускают одновременное выполнение нескольких запросов.

...