1. Задавайте здесь вопросы о коде, которые не подходят в другие разделы, такие как:
    Дизайн > Верстка
    PHP > Как сделать на PHP
    Скрыть объявление

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

Тема в разделе "Web Coding", создана пользователем elcaste, 3 фев 2008.

Статус темы:
Закрыта.
Модераторы: latteo
  1. elcaste

    elcaste

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

    PHP:
    $fp=fsockopen($HostName$HostPort$errno$errstr30); 
    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($fp300); 

        
    fputs($fp$out);
        while (!
    feof($fp)) {
            
    $ech.= fgets($fp,128);
            }
        }
    в конце же процедуры, когда цикл доходит до EOF - он зависает секунд этак на 10-15... подозреваю, что так быть не должно :)
    Где может быть бок?
    :nezn:

    Стоит PHP5.

    Спасибо.
     
  2. Jeurey

    Jeurey

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

    ЗЫ. Понятие процедуры в php? :ah:
     
  3. itex

    itex

    Регистр.:
    15 ноя 2007
    Сообщения:
    274
    Симпатии:
    64
    $out .= "Connection: Keep-Alive\r\n";
    В этом проблема, сервер ждет еще порции данных от вас, и только потом закрывает по таймауту, чтоб сразу закрыть соединение нужно использовать Connection: Close или самому рвать соединение, когда получено достаточно данных.
     
  4. mentanos

    mentanos Постоялец

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

    те же скрипты при запуске с нескольких разных серверов задержек не дают. те же скрипты под php4 задержек не давали. фиг знает это у меня, конфиг php переносил без изменений...
     
  5. nnmkayf

    nnmkayf

    Регистр.:
    25 июл 2007
    Сообщения:
    153
    Симпатии:
    98
    К вопросу о проблеме смена на
    PHP:
    $each .= fgets($fp);
    помогла?

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

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

    mentanos Постоялец

    Регистр.:
    27 дек 2007
    Сообщения:
    128
    Симпатии:
    35
    внимательно читаем мануал к fgets:
    length указывает размер буфера чтения, а не то, сколько символов нужно выжать из соединения
     
  7. Avtandil

    Avtandil Создатель

    Регистр.:
    30 сен 2006
    Сообщения:
    30
    Симпатии:
    24
    Пример запроса по методу 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>"// вывод контента или заголовков в виде текста
     
  8. Jeurey

    Jeurey

    Регистр.:
    13 сен 2006
    Сообщения:
    419
    Симпатии:
    576
    А размер буфера чтения это не есть количество байт? :D
     
  9. mentanos

    mentanos Постоялец

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

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

    Jeurey

    Регистр.:
    13 сен 2006
    Сообщения:
    419
    Симпатии:
    576
    Гы. Разберем подробнее.

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

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

    PS
    EOL - End of Line
    EOF - End of File
     
Статус темы:
Закрыта.