Ответ от сервера. Тормоза с получением через fgets().

Статус
В этой теме нельзя размещать новые ответы.

elcaste

Постоялец
Регистрация
30 Ноя 2007
Сообщения
322
Реакции
175
Стандартно подключаюсь через сокеты:

PHP:
$fp=fsockopen($HostName, $HostPort, $errno, $errstr, 30); 
if (!$fp) 
    { 
    echo "$errstr ($errno)<br />\n"; 
    } 
else 
    { 
    $out  = "POST $Url HTTP/1.1\r\n"; 
    $out .= "Host: $HostName\r\n"; 
    $out .= "Content-type: application/x-www-form-urlencoded\r\n"; 
    $out .= "Referer: http://newblog.com/editpost.asp\r\n"; 
    $out .= "Accept-Language: ru\r\n"; 
    $out .= "Connection: Keep-Alive\r\n"; 
    $out .= "Cache-Control: no-cache\r\n";
    $out .= "\r\n";
    $out .= "Cache-Control: no-cache\r\n"; 
    $out .= "Content-length: ".strlen($PostData)."\r\n\r\n".$PostData; 

    stream_set_timeout($fp, 300); 

    fputs($fp, $out);
    while (!feof($fp)) {
        $ech.= fgets($fp,128);
        }
    }

в конце же процедуры, когда цикл доходит до EOF - он зависает секунд этак на 10-15... подозреваю, что так быть не должно :)
Где может быть бок?
:nezn:

Стоит PHP5.

Спасибо.
 
Чет я не совсем понимаю, зачем читать строку (!?) по 128 байт. Можно ведь просто в цикле
PHP:
$each .= fgets($fp);
Второе - где обнуление переменной $each? :)
Не вижу смысла в
PHP:
stream_set_timeout($fp, 300);

Попробуй все-таки убрать блочное чтение строки... Сдается, там не очень все хорошо.

ЗЫ. Понятие процедуры в php? :ah:
 
$out .= "Connection: Keep-Alive\r\n";
В этом проблема, сервер ждет еще порции данных от вас, и только потом закрывает по таймауту, чтоб сразу закрыть соединение нужно использовать Connection: Close или самому рвать соединение, когда получено достаточно данных.
 
If a connection opened by fsockopen() wasn't closed by the server, feof() will wait until a timeout has been reached to return TRUE. The default timeout value is 60 seconds. You may use stream_set_timeout() to change this value.

с другой стороны, у меня на машине (win xp) после обновления php с 4 на 5 появились непонятные задержки. php страницы выдаются целиком, но браузер чего-то ждет (ie, opera, fox). ВСЕ скрипты, использующие сокеты для http запросов (connection: close) и разрывающие соединение по признаку feof==true или fgets==false чего-то выжидают перед тем как завершить работу.

те же скрипты при запуске с нескольких разных серверов задержек не дают. те же скрипты под php4 задержек не давали. фиг знает это у меня, конфиг php переносил без изменений...
 
К вопросу о проблеме смена на
PHP:
$each .= fgets($fp);
помогла?

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

Если следовать этой логике совет Jeurey должен помочь, тем не менее хотелось-бы услышать подтверждение, что это так.
 
К вопросу о проблеме смена на
PHP:
$each .= fgets($fp);
помогла?

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

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

внимательно читаем мануал к fgets:
string fgets ( resource handle [, int length] )



Gets a line from file pointer.
Parameters

....

length

Reading ends when length - 1 bytes have been read, on a newline (which is included in the return value), or on EOF (whichever comes first). If no length is specified, it will keep reading from the stream until it reaches the end of the line.

Note: Until PHP 4.3.0, omitting it would assume 1024 as the line length. If the majority of the lines in the file are all larger than 8KB, it is more resource efficient for your script to specify the maximum line length.

length указывает размер буфера чтения, а не то, сколько символов нужно выжать из соединения
 
Пример запроса по методу POST:
PHP:
$host = 'microsoft.com';
$sock = fsockopen($host,80,$errno,&$errstr,30);
if (!$sock) die("Socket error $errno: $errstr");
 
$uri = '/admin/';
$data = urlencode('login=admin&password=пароль');
$datalen = strlen($data);
 
fputs($sock,"POST $uri {$_SERVER['SERVER_PROTOCOL']}
Host: $host
Accept: {$_SERVER['HTTP_ACCEPT']}
Accept-Language: {$_SERVER['HTTP_ACCEPT_LANGUAGE']}
Accept-Charset: {$_SERVER['HTTP_ACCEPT_CHARSET']}
User-Agent: {$_SERVER['HTTP_USER_AGENT']}
Content-Type: application/x-www-form-urlencoded
Content-Length: $datalen
Connection: {$_SERVER['HTTP_CONNECTION']}
Referer: http://$host/
 
$data");
unset($buf);
do { // чтение заголовков ответа
  $line = fgets($sock,512); $buf .= $line;
} while ($line!="\r\n" && !feof($sock));
 
// анализ заголовков
$content_sent = ...
...
// конец анализа заголовков
 
if ($content_sent){ // ожидается контент
  unset($buf);
  while (!feof($sock)) $buf .= fread($sock,8192); // чтение контента
}
fclose($sock);
header('Content-Type: text/plain');
echo "<xmp>$buf</xmp>"; // вывод контента или заголовков в виде текста
 
внимательно читаем мануал к fgets:


length указывает размер буфера чтения, а не то, сколько символов нужно выжать из соединения

А размер буфера чтения это не есть количество байт? :D
 
А размер буфера чтения это не есть количество байт? :D

буфер чтения указывает сколько памяти выделять под операцию чтения. как написано в мануале, чтение прерывается по достижению максимальной длины буфера ИЛИ по концу строки ИЛИ по концу ввода. а не обязательно по 100% заполнению "количества байт" :ppppp

в результате если храбро
Чет я не совсем понимаю, зачем читать строку (!?) по 128 байт. Можно ведь просто в цикле
PHP код:
$each .= fgets($fp);

то при поступлении на ввод длинной строки она целиком суется в память, пока разрешенной памяти хватит. ц-е-л-и-к-о-м. будь то 100 байт или 1гиг
 
Гы. Разберем подробнее.

Возьмем размер страницы в 50кб и состоящей из 25 строк.
В первом случае будет 400 итераций цикла (50*1024/128) (минимум, ибо не всегда конец строки будет совмещаться с байтом, четным 128), а во втором всего 25. Ну и о чем мы говорим?

В по поводу размера буфера чтения... для fgets это количество байт от pointer, которые мы берем за итерацию. А память мы берем под символы => можно размер буфера считать в символах. Конечно, не забываем про EOL && EOF :)

PS
EOL - End of Line
EOF - End of File
 
Статус
В этой теме нельзя размещать новые ответы.
Назад
Сверху