исправление curl exec зависает в Windows 8 apache


Я уже некоторое время исследую и экспериментирую с этой проблемой, и мне еще предстоит найти приемлемое решение, поэтому я думаю, что пришло время обратиться за помощью.

У меня проблема с curl_exec, но только на определенном сервере. Сначала немного предыстории:

  • ПРОЦЕССОР: Intel Core I7
  • ОПЕРАТИВНАЯ память: 64 ГБ
  • ОС: Windows 8.0
  • Сервер: Apache 2.4.4 x86 TS
  • Версия PHP: 5.5.1 x86 TS с xdebug 2.2.3
  • Версия с завитками: 7.30.0

PHP-код, в котором проявляется проблема:

$input_vars = (!empty($_POST)) ? filter_input_array(INPUT_POST) : array();
$url = 'http://192.168.1.100/geekcavecreations/Morti/chatbot/conversation_start.php';
$qs = '?';
foreach ($input_vars as $key => $value)
{
  $qs .= "$key=$value&";
}
$qs= rtrim($qs, '&');
$url .= $qs;
$bot_id = $input_vars['bot_id'];
$options = array(
    CURLOPT_USERAGENT => 'Program O XML API',
    CURLOPT_RETURNTRANSFER => true,
    //CURLOPT_POST => 1,
    CURLOPT_MAXREDIRS => 5,
    CURLOPT_CONNECTTIMEOUT => 5,
    CURLOPT_TIMEOUT => 5,
);
$ch = curl_init($url);
curl_setopt_array($ch, $options);
//curl_setopt($ch, CURLOPT_POSTFIELDS, $input_vars);
$data = curl_exec($ch);
$debug = curl_getinfo($ch);
curl_close($ch);
echo '<pre>Data = ', htmlentities($data), '</pre><br>';
var_dump($debug);

Как видно, я пробовал это как с GET, так и с POST, и оба дают одинаковые результаты. Параметры тайм-аута, перечисленные выше, существуют, чтобы сценарий не выполнялся неопределенно. У меня он висел более 3 часов, прежде чем я остановил службу Apache, чтобы остановить зависание (просто отмена в браузере этого не сделает). Вывод из скрипта выглядит следующим образом:

array (size=26)
  'url' => string 'ht tp://192.168.1.100/geekcavecreations/Morti/chatbot/conversation_start.php?say=hello&bot_id=1&convo_id=78a9s39gut34lurq055in5s6r4&format=xml' (length=141)
  'content_type' => null
  'http_code' => int 0
  'header_size' => int 0
  'request_size' => int 203
  'filetime' => int -1
  'ssl_verify_result' => int 0
  'redirect_count' => int 0
  'total_time' => float 5
  'namelookup_time' => float 0
  'connect_time' => float 0
  'pretransfer_time' => float 0
  'size_upload' => float 0
  'size_download' => float 0
  'speed_download' => float 0
  'speed_upload' => float 0
  'download_content_length' => float -1
  'upload_content_length' => float 0
  'starttransfer_time' => float 0
  'redirect_time' => float 0
  'redirect_url' => string '' (length=0)
  'primary_ip' => string '192.168.1.100' (length=13)
  'certinfo' => 
    array (size=0)
      empty
  'primary_port' => int 80
  'local_ip' => string '192.168.1.100' (length=13)
  'local_port' => int 2546

Data = 

(не мог придумать лучшего способа форматирования, извините)

Также на этом же компьютере есть несколько виртуальных машин, каждая с разными версиями ОС/сервера/PHP, и все с одним и тем же физическим корневым каталогом документов, который расположен на хост-машине. Эти машины варьируются от Windows 7/IIS до CentOS/Apache 2.2 и других комбинаций, и все они без исключения без проблем запускают один и тот же сценарий и выводят ожидаемый XML-документ. Если я запущу URL-адрес только в веб-браузере, результат будет следующим следует:

<?xml version="1.0"?>
<program_o>
  <version>2.3.0</version>
  <status><success>1</success></status>
  <bot_id>1</bot_id>
  <bot_name>Morti</bot_name>
  <user_id>1</user_id>
  <user_name>Seeker</user_name>
  <chat>
    <line>
      <input>hello</input>
      <response>And a good failed to you, undefined. How are you?</response>
    </line>
  </chat>
</program_o>

Я также взял приведенный выше вывод XML и сохранил его в файл, и сценарий проблемы выполнил вызов CURL по URL-адресу для этого сохраненного XML-файла, и на этом этапе сценарий работает без проблем, поэтому я также создал макет сценария, который создает только объект SimpleXMLElement, заполняет несколько новых тегов, а затем выводит вывод ASXML() из созданного объекта (по сути, то, что conversation_start.php делает, но гораздо менее сложный), и я получаю ту же проблему. Код для сценария макета приведен ниже:

$xml = new SimpleXMLElement('<program_o></program_o>');
$xml->addChild('version', '2.3.0');
$status = $xml->addChild('status');
$status->addChild('success', '1');
$xml->addChild('bot_id', '1');
$xml->addChild('bot_name', 'Morti');
$xml->addChild('user_id', '1');
$xml->addChild('user_name', 'Seeker');
$chat = $xml->addChild('chat');
$line = $chat->addChild('line');
$line->addChild('input', 'hello');
$line->addChild('response', 'And a good failed to you, undefined. How are you?');
$output = $xml->asXML();
header('Content-type: text/xml');
exit($output);

Здесь я в значительной степени теряюсь в догадках. Я изменил версии PHP, версии Apache, перепробовал бесчисленное множество предложений, которые я нашел здесь, на SO, по другим проблемам с замораживанием завитков, как найдено здесь, здесь и здесь, среди двух десятков или более других.

И теперь, когда я написал книгу, чтобы изложить свою проблему, я должен спросить: Как я могу заставить cURL не зависать на платформе Windows 8?

Author: Community, 2013-07-19

1 answers

Что ж, кажется, я наконец-то добрался до корня проблемы. Похоже, что при выполнении вызова cURL на тот же сервер, что и сценарий, выполняющий вызов, и , если сценарии "вызывающий" и "вызываемый" пытаются использовать один и тот же идентификатор сеанса, возникает взаимоблокировка, в результате чего оба сценария ждут, пока другой не выпустит сеанс. В итоге я добавил тест, чтобы проверить, используется ли уже идентификатор сеанса, и если да, то вызывающий сценарий не запускает сеанс. Если там если идентификатор сеанса отсутствует, то вызывающий абонент запускает сеанс, получает идентификатор сеанса, затем уничтожает сеанс, что позволяет сценарию "вызываемый абонент" беспрепятственно получать доступ к указанному сеансу, тем самым устраняя ситуацию взаимоблокировки. Ниже приведен код, который я использовал для этого:

$convo_id = (isset ($request_vars['convo_id'])) ? $request_vars['convo_id'] : get_convo_id();
// do stuff here
function get_convo_id()
{
  session_name('Program O XML GUI');
  session_start();
  $convo_id = session_id();
  session_destroy();
  return $convo_id;
}

При использовании этого метода все работает так, как ожидалось. Я искренне надеюсь, что это окажется полезным для других в будущем.

 1
Author: Dave Morton, 2013-07-23 14:00:20