English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Краткое рассмотрение методов решения проблемы с превышением времени ожидания при доступе к серверу и интерфейсу PHP

【Доступ к HTTP】

Обычно мы используем множество методов для доступа к HTTP,主要包括: curl, socket, file_get_contents() и т.д.

Если сервер не отвечает в течение длительного времени, это может быть трагедией, так как легко можно убить весь сервер, поэтому при доступе к HTTP также необходимо учитывать проблему таймаутов.

[Доступ к HTTP через CURL]

CURL - это один из常用的 библиотек для доступа к интерфейсам протокола HTTP, которая имеет высокую производительность и некоторые функции поддержки параллельного выполнения.

CURL:

curl_setopt($ch, opt) может устанавливать некоторые настройки таймаутов, включая:

(Важно) CURLOPT_TIMEOUT - устанавливает максимальное время выполнения в секундах, которое позволяет cURL.

(Важно) CURLOPT_TIMEOUT_MS - устанавливает максимальное время выполнения в миллисекундах, которое позволяет cURL. (Добавлен в cURL 7.16.2. Доступен с PHP 5.2.3.)

CURLOPT_CONNECTTIMEOUT - время ожидания перед установлением соединения, если установлено в 0, то ожидание неограниченное время.

CURLOPT_CONNECTTIMEOUT_MS время ожидания при попытке подключения, в миллисекундах. Если установлено в 0, то ожидание бесконечно. Добавлено в cURL 7.16.2. С PHP 5.2.3 доступно.

CURLOPT_DNS_CACHE_TIMEOUT устанавливает время хранения информации DNS в памяти, по умолчанию 120 секунд.

Обычное время ожидания cURL:

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL,$url);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

curl_setopt($ch, CURLOPT_TIMEOUT, 60); //Достаточно установить количество секунд

curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

curl_setopt($ch, CURLOPT_USERAGENT, $defined_vars['HTTP_USER_AGENT']);

Использование обычного времени ожидания в секундах cURL:

curl_setopt($ch, CURLOPT_TIMEOUT, 60);

Если cURL нужно использовать время ожидания в миллисекундах, нужно добавить:

curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);

Или:

curl_setopt ($ch, CURLOPT_NOSIGNAL, true); поддерживает настройку времени ожидания в миллисекундах

Пример запроса cURL с мillisecondовым временем ожидания:

<?php
if (!isset($_GET['foo'])) {
//Клиент
    $ch = curl_init('http://example.com/');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_NOSIGNAL, 1);  
//Внимание, время ожидания в миллисекундах должно быть установлено
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200); 
//Время ожидания в миллисекундах, добавлено в cURL 7.16.2. С PHP 5.2.3 можно использовать
    $data = curl_exec($ch);
    $curl_errno = curl_errno($ch);
    $curl_error = curl_error($ch);
    curl_close($ch);
    if ($curl_errno > 0) {
        echo "cURL Error ($curl_errno): $curl_error\n";
    }
        echo "Received data: $data\n";
    }
}
// Server
    sleep(10);
    echo "Done.";
}
?>

Другие полезные советы:

1. По опыту можно сказать, что: версия cURL >= libcurl/7.21.0, мillisecondовое ожидание определенно сработает, запомните это.

2. Проблемы с мillisecondовым ожиданием в curl_multi... Поддержка мillisecondового ожидания для одного доступа, но при параллельных вызовах curl_multi не точна

[Доступ к HTTP через потоковую обработку]

Кроме curl, мы часто используем fsockopen или функции работы с файлами для обработки протокола HTTP, поэтому обработка времени ожидания в этой области также обязательна.

Обычно можно просто установить время ожидания подключения, но для обработки времени ожидания потока чтения необходимо отдельно обрабатывать.

Напишите свой код обработки:

$tmCurrent = gettimeofday();
$intUSGone = ($tmCurrent['sec'] - $tmStart['sec']) * 1000000
+ ($tmCurrent['usec'] - $tmStart['usec']);
if ($intUSGone > $this->_intReadTimeoutUS) {
return false;
}

или используйте встроенные функции обработки потоков stream_set_timeout() и stream_get_meta_data():

<?php 
// Timeout в секундах 
$timeout = 5; 
$fp = fsockopen("example.com", 80, $errno, $errstr, $timeout); 
if ($fp) { 
    fwrite($fp, "GET / HTTP/1.0\r\n"); 
    fwrite($fp, "Host: example.com\r\n"); 
    fwrite($fp, "Connection: Close\r\n\r\n"); 
    stream_set_blocking($fp, true);  
//Важное, установите режим не блокирующего выполнения
    stream_set_timeout($fp,$timeout);  
//Установить таймаут
    $info = stream_get_meta_data($fp); 
    while ((!feof($fp)) && (!$info['timed_out'])) { 
        $data .= fgets($fp, 4096); 
        $info = stream_get_meta_data($fp); 
        ob_flush; 
        flush(); 
    } 
    if ($info['timed_out']) { 
        echo "Connection Timed Out!"; 
    } 
        echo $data; 
    } 
}

Таймаут file_get_contents:

<?php
$timeout = array(
  'http' => array(
    'timeout' => 5 
//Установить время ожидания, единицы измерения - секунды
  )
);
$ctx = stream_context_create($timeout);
$text = file_get_contents("http://example.com/", 0, $ctx);
?>

Таймаут fopen:

<?php
$timeout = array(
  'http' => array(
    'timeout' => 5 
//Установить время ожидания, единицы измерения - секунды
  )
);
$ctx = stream_context_create($timeout);
if ($fp = fopen("http://example.com/", "r", false, $ctx)) {
 while( $c = fread($fp, 8192)) {
  echo $c;
 }
 fclose($fp);
}
?>

Вот и все, что я хотел рассказать вам о кратком рассмотрении методов решения проблемы таймаутов при обработке PHP и доступе к интерфейсу. Надеюсь, вам понравится и вы поддержите tuorial!

Основной учебник
Рекомендуем для просмотра