Зависание скрипта при работе с сокетами,помогите!

mr.GOD

Новичок
Зависание скрипта при работе с сокетами,помогите!

OS : FreeBSD 4.10
PHP 4.3.11
Apache :1.3.33

Имеется скрипт который ходит по списку урлов(список очень большой) и собирает ссылки определенные , но при прохождении определенного(все время разного) количества адресов просто виснет , причем все время на разных адресах.
Вот функция :
PHP:
SendRequest($http_request,$host,$port){

$res["RESULT"]=false;
$res["RESPONSE"]="";

$f=@fsockopen($host,$port,$errno,$errstr);
if (!$f){
$res["RESPONSE"]="Can't open socket. Error code: \"$errno\".Error string: $errstr.";
return $res;
}

socket_set_blocking($f,0);  
socket_set_timeout($f,5);  	
if (@fputs($f,$http_request)==-1) {
  	@fclose($f); 
 	$res["RESPONSE"]="Can't send query to server! It is impossible"; 
 	return $res;  
}  
while (!feof($f))  		
	$res["RESPONSE"].=fread($f,128);  
  	@fclose($f);
  	$res["RESULT"]=true;
  	return $res;	  	
}
Ну все обычно , но дело в том что когда я сделал детальный лог этой функции, то скрипт останавливается вот здесь :
PHP:
while (!feof($f)) 
 	$res["RESPONSE"].=fread($f,128);
и все , и некакие таймауты и неблокирующий режим не воздействуют на это дело :(

Уважаемые , помогите понять в чем тут дело ?
Заранее благодарен.
 

mr.GOD

Новичок
Автор оригинала: SiMM
> в чем тут дело ?
feof($f) === false
Уважаемый , а можно поподробней с этого места, т.к. я немного не понял к чему это написано,пояснить темному человеку,заранее спасибо.
 

SiMM

Новичок
Что тут может быть непонятного? С какой радости должен закончиться цикл, если feof возвращает false? Делайте выводы о длине запрошенного контента на основании хидера Content-Length
 

mr.GOD

Новичок
Не подумал,туплю,большое спасибо еще раз.

-~{}~ 22.09.05 19:10:

Автор оригинала: SiMM
Что тут может быть непонятного? С какой радости должен закончиться цикл, если feof возвращает false? Делайте выводы о длине запрошенного контента на основании хидера Content-Length
Возвращаясь... сделал поспешные выводы по поводу вашего совета.Однако чтобы оный хидер получить нужно все равно сделать запрос.
Однако проблема в том что , посылая HEAD-запрос чтобы определить длину документа , я не знаю длины ответа на этот запрос , и возникает так же проблема , например при посылке этого HEAD-запрос в момент когда я получаю ответ , сервер будет перезагружен например, то опять начинается бесконечное ожидание...

Подскажите , у кого были подобные проблемы как обойтись без feof() и при этом отвалится по таймауту если сервер вдруг перестал отдавать данные.

Хелп!:(
 

SiMM

Новичок
> посылая HEAD-запрос чтобы определить длину документа , я не знаю длины ответа на этот запрос
А её и не надо знать. Заголовок любого отклика на запрос отделяется от контента пустой строкой.
PHP:
$req = 'HEAD ....';
$fp = fsockopen('...',80);
fwrite($fp,$req);
while (strlen($str = trim(fgets($fp,1024)))) echo $str."<br>\n";
 

mr.GOD

Новичок
не хочу показаться излишнем назойлевым , но при HEAD-запросе я как раз и получаю один заголовки без контента,однако представим себе ситуацию что сервер не смог отдать все заголовки.Т.е. я получил половину заголовков и продолжаю ждать оставшиюся часть бесконечно долго , т.к. сервер не может дальше их отдавать по каким-то причинам.

-~{}~ 22.09.05 19:38:

мое имхо что таймаут нужен в любом случае , но он почему-то не работает :(,в том чилсе неблокирующий режим также , буду еще пробывать другую версию пхп , может это выход ?

-~{}~ 22.09.05 19:51:

попробывал вашу конструкцию , данных не получаю вообще.
 

SiMM

Новичок
> но при HEAD-запросе я как раз и получаю один заголовки без контента
А это никак не противоречит моему утверждению. Длина контента может быть и нулевой.
 

mr.GOD

Новичок
но при вашем варианте я вообще не получаю данных т.е. цикл не делает не одной итэрации.
 

SiMM

Новичок
> цикл не делает не одной итэрации.
Этого не может быть, потому что этого не может быть. Разве что сервер действительно не выдаёт отклика. Естесственно тут никаких других вариантов, кроме таймаута, быть не может.
 

Profic

just Profic (PHP5 BetaTeam)
PHP:
var_dump(ssocket_set_timeout($f, 5));
$data = '';
while ($buf = fread($f, 1024)) {
    $data .= $buf;
}
Посылать либо http/1.0 запрос, либо заголовок Connection: close
 

mr.GOD

Новичок
2Simm
Я тупо меняю
PHP:
while (!feof($f))$data .= fread($f,1);
на
PHP:
while (strlen($data = trim(fgets($f,1024))))
и отклик там есть , но тем неменее ... не знаю может я дурак :confused:

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

И моя задача даже если нет возможности обратится к документу , хотя бы не вызвать это зависание.

2Profic
PHP:
while ($buf = fread($f)) {       $data .= $buf;   }
аналогично , и если разрешите поделюсь соображениями почему это происходит , а потому что оба варианта не возвращают булево значение и как следствие не одной итерации цикла.В то время как с feof() все как и должно быть , за исключением того что он дает бесконечный цикл...

С запросом все в порядке 100 %
Connection: close - есть . Протокол HTTP 1.1
 

SiMM

Новичок
> оба варианта не возвращают булево значение
[m]language.types.boolean#language.types.boolean.casting[/m]
 

jdoe

Новичок
с неблокирующими сокетами лучше использовать socket_select.
поллинг в таком виде как минимум странен.
 

mr.GOD

Новичок
Автор оригинала: SiMM
> оба варианта не возвращают булево значение
[m]language.types.boolean#language.types.boolean.casting[/m]
читал , но тем неменее факт остается фактом
1.мой вариант дает данные.
2.ваш нет.
Возможно false возвращается сразу.Почему?Без понятия...

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

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

-~{}~ 22.09.05 22:39:

PHP:
do { 
 $_data = fread($f,50000); 
          if (strlen($_data) == 0) 
         {
                          break;                 
         }         
         $data .= $_data;         
            } while(true);
вот такая конструкция работает без проблем , но после прохождения некоторого количества адресов все равно виснет :)
 

whirlwind

TDD infected, paranoid
> в чем тут дело ?
feof($f) === false
Объясните мне тупому чем отличается !feof($f) от feof($f) === false в контексте описанного цикла?

С какой радости должен закончиться цикл, если feof возвращает false? Делайте выводы о длине запрошенного контента на основании хидера Content-Length
С такой радости, что когда сервер закроет сокет, принимающая строна получит EOF.

mr.GOD вот такая конструкция работает без проблем , но после прохождения некоторого количества адресов все равно виснет

Ну так выясни что это за адрес, и телнетом на него. Может быть тут вовсе не в твоем скрипте дело.
 

mr.GOD

Новичок
2whirlwind
С такой радости, что когда сервер закроет сокет, принимающая строна получит EOF
а он может его и не закрыть , например если его перезагрузили...

выяснить это проблемотично т.к. список сайтов все время меняется , но на 99 % что там просто "даун-сервер" или банально имеет место быть коммуникационный сбой,т.е. мой скрипт не получает EOF.Но мне тем немнее нужно чтобы скрипт продолжал свою работу.
 

SiMM

Новичок
> а он может его и не закрыть
И, если я не ошибаюсь, при Connection: keep-allive
PS: специально обращаю внимание некоторых, что никакого запроса тут не приводилось.
 

mr.GOD

Новичок
у меня Connection: Close
вы немного не понимаете о чем я , вот абсолютно реальная ситуация .
В момент времени А я открываю сокет и посылаю запрос удаленному серверу , в момент времени B сервер начинает посылать мне ответ , в момент времени C он уже послал мне там 400 байт , но это даже не весь заголовок , и в этот момнет времени C , добрый админ делает ребут.
Я сижу жду ответа(чтоб получить хотя бы нужный мне Content-Lenght) до бесконечности... т.к. соединение не будет закрыто уже больше не когда удаленным сервером.

-~{}~ 23.09.05 11:52:

и учитываю что адресов много и сервера находятся в разных ДЦ в разных частях планеты , то такие проблемы возникают неприменно , с чем я и столкнулся.И мой скрипт иногда в "хорошую погоду" отрабатывает весь список адресов и завершает верно свою работу, от чего эта погода зависит остается только догадываться...

-~{}~ 23.09.05 12:05:

запрос , пожайлуста :
PHP:
$request['HEAD'] = "HEAD / HTTP/1.1\n";
$request['HEAD'] .= "Host: www[точка]yandex[точка]ru\n"; 
$request['HEAD'] .= "User-Agent: PHP Script\n";
$request['HEAD'] .= "Accept-Language: ru\n";
$request['HEAD'] .= "Accept-Ranges: bytes\n";
$request['HEAD'] .= "Accept: text/html\n";
$request['HEAD'] .= "Pragma: no-cache\n";
$request['HEAD'] .= "Connection: Close\n\n";
-~{}~ 23.09.05 12:08:

*[точка] - форум просто туда сразу вставляет свой тэг для урла
 

whirlwind

TDD infected, paranoid
> а он может его и не закрыть
Все равно будет EOF. Главное избавиться от блокировки. А при keep-alive время поддержки коннекта определяется сервером и чаще всего это величина далека от infinity.

Если есть возможность и ты уверен, что виснет на fread, заюзай SIGALRM. Если нет, но все равно хочется, то fork/pipe/select. А вообще по моему куда проще узнать таки на каком сайте глючит. Хотя бы shell_exec("echo $host:$port > lastsite"), если влом писать нормальный отладочный код.
 
Сверху