Параллельные HTTP-запросы в PHP с использованием классов PECL HTTP


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

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


проблема

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

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

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

В частности, мне нужно отправлять данные POST одновременно с набором 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 : Я хотел бы использовать функции HTTP PECL как:

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

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

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

    Я уверен, что HttpRequestPool – это то, что вы ищете.

    Чтобы разработать немного, вы можете использовать forking для достижения того, что вы ищете, но это кажется излишне сложным и не очень полезным в контексте HTML. Пока я не тестировал, этот код должен быть таким:

     // пусть $ request представляет собой массив запросов для отправки
     $ pool = new HttpRequestPool ();
     foreach ($ request as $ request) {
       $ Бассейн-> присоединять ($ запроса);
     }
     $ Бассейн-> отправить ();
     foreach ($ pool as $ request) {
       // делать что-то
     }
    

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

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

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

     $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 reponses извлекается в полупараллеле, так как socket_read не дожидается ответа, но возвращает, если сокет-буфер еще не заполнен.

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

    В последнее время друг указал мне на 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-> request as $ request) {…}

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

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

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

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