Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Problem z zatrzymującym się skryptem wysyłającym dane na serwer
Forum PHP.pl > Forum > PHP
marcinpl87
Witam
mam zdefiniowane kilka serwerów które pinguję i w pętli wywołuję wiele razy taki kod:
  1. if ($pinghandle = fsockopen($host, 80, $errno, $errstr, 30)) {
  2. @fputs( $pinghandle, $httpReq );
  3. while (!feof($pinghandle)) {
  4. $pingresponse = @fgets( $pinghandle, 128 );
  5. }
  6. @fclose( $pinghandle );
  7. }
w zmiennej $host mam adres serwera który będę pingował a w $httpReq jest to co do niego wysyłam. Pętla ma kilka tysięcy interacji i przy każdej iteracji mam zapytanie które mi zwiększa o 1 pewien rekord w bazie (to taki mój licznik pingnięć). No i bardzo często (średnio raz na 4 razy) w połowie pętli licznik zatrzymuje się i stoi w miejscu, choć w konsoli widzę że proces jest uruchomiony. Skrypt uruchamiałem albo z crona albo z konsoli bo wykonanie trwa kilka godzin więc jakbym go w przeglądarce uruchomił to raczej miałbym timeouta smile.gif.
Najgorsze jest to że w funkcji fsockopen mam timeout w ostatnim argumencie i nawet jak ustawię ten timeout na 1 sekundę to widzę po komunikatach że ostatni komunikat jest przed tą funkcją i w tym miejscu iteracja pętli się zawiesza.
Podpowiedzcie co tu zrobić żeby zdefiniować jakiś działający timeout żeby w przypadku nie odpowiadającego serwera skrypt jechał dalej i nie zawieszał mi się tak jak teraz.
marcinpl87
witam, wlepiłem funkcję stream_set_timeout (nie wiem czy w dobrym miejscu) i co kawałek kodu dodałem echo 1 2 3 4 5 6 żebym wiedział w którym momencie skrypt się zatrzymał. Cały ten kod który poniżej wklejam jest wywoływany w pętli wiele razy:
  1. echo $host."\n".'<br />';
  2. echo '1';
  3. if ($pinghandle = fsockopen($host, 80, $errno, $errstr, 10)) {
  4. echo '2';
  5. stream_set_timeout($pinghandle, 10);
  6. echo '3';
  7. @fputs( $pinghandle, $httpReq );
  8. echo '4';
  9. while (!feof($pinghandle)) {
  10. $pingresponse = @fgets( $pinghandle, 128 );
  11. }
  12. echo '5';
  13. @fclose( $pinghandle );
  14. }
  15. else {
  16. echo "TIMEOUT ALBO ERROR: $errno - $errstr<br />\n";
  17. }
  18. echo '6<br />'."\n";
no i gdy skrypt się "zawiesił" zajrzałem do logów i na końcu logu było coś takiego:
  1. blogsearch.google.com
  2. <br />123456<br />
  3. ping.syndic8.com
  4. <br />123456<br />
  5. rpc.blogrolling.com
  6. <br />1234
więc jak widać skrypt zawiesił się gdzieś pomiędzy echo 4 a echo 5, w tej pętli while...
podpowiedzcie proszę - jak to poprawić?
yevaud
http://php.net/manual/en/function.feof.php
If a connection opened by fsockopen() wasn't closed by the server, feof() will hang.
XianN
Cytat
Warning
If a connection opened by fsockopen() wasn't closed by the server, feof() will hang.


Zobacz do manuala feof, jest tam kod korego mozesz uzyc, aby rozwiazac problem.
marcinpl87
witam. rozumiem że chodziło o tą pętlę do...while
zmodyfikowałem więc mój kod, teraz wygląda tak:
  1. echo $host."\n".'<br />';
  2. echo '1';
  3. if ($pinghandle = fsockopen($host, 80, $errno, $errstr, 10)) {
  4. echo '2';
  5. stream_set_timeout($pinghandle, 10);
  6. echo '3';
  7. @fputs( $pinghandle, $httpReq );
  8. echo '4';
  9. do {
  10. $pingresponse = @fgets( $pinghandle, 128 ); //wysyla dane o pingu
  11. } while (!feof($pinghandle));
  12. fclose($pinghandle);
  13. }
  14. echo '6<br />'."\n";
ale skrypt znowu zatrzymuje się po 1234 czyli przed do{}
co robię źle?
XianN
No wlasnie nie o to winksmiley.jpg Teraz mozesz poczytac czym rozni sie while... od do...while (czyli tym, ze do... zrobi przynajmniej raz costam, sprawdzanie warunku petli wykonuje sie _PO_ wykonaniu petli)

A chodzi o to, ze fgets ma zabrac 127 bitow, ew linie ze znakiem jej konca lub napotkac koniec strumienia. Jesli trafisz na serwer, ktory nie zamyka socketa poprawnie to zawisniesz w tym miejscu, bo feof dalej zwraca false, z fgets nie ma juz nic do przeczytania. Zastosuj ten kod z safe_feof.

To moze byc jakos tak (nie mam teraz czasu, zeby zobaczyc czy to bedzie poprawnie...):
  1. <?php
  2. function safe_feof($fp, &$start = NULL) { // w manualu tutaj jest literowka
  3. $start = microtime(true);
  4.  
  5. return feof($fp);
  6. }
  7.  
  8. $start = NULL;
  9. $timeout = ini_get('default_socket_timeout');
  10.  
  11. echo $host."\n".'<br />';
  12. echo '1';
  13.  
  14. if ($pinghandle = fsockopen($host, 80, $errno, $errstr, 10))
  15. {
  16. @fputs( $pinghandle, $httpReq ); // to wysyla...
  17.  
  18. while(!safe_feof($fp, $start) && (microtime(true) - $start) < $timeout)
  19. {
  20. $pingresponse = @fgets( $pinghandle, 128 ); //wysyla dane o pingu <---- wcale nie! To nie wysyla, tylko odbiera informacje [!!!!!!]
  21. }
  22. fclose($pinghandle);
  23. }
  24. else
  25. {
  26. echo 'cos nie poszlo';
  27. }


A tak poza tym, to dlaczego uparles sie na socket? Chcesz zobaczyc czy dziala serwis, to zamiast robic to w ten sposob mozesz uzyc file_get_contents:
  1. $opts = array(
  2. 'http'=>array(
  3. 'method'=>"GET",
  4. 'header'=>"Accept-language: en\r\n" .
  5. "Cookie: foo=bar\r\n"
  6. )
  7. );
  8.  
  9. if ($context = stream_context_create($opts))
  10. {
  11. if (file_get_contents('http://www.google.pl/', false, $context, 0, 10)) // z ograniczeniem na dane, bo nie obchodzi nas co tam jest tylko czy w ogole jest cokolwiek
  12. {
  13. echo 'dziala';
  14. }
  15. }
neverever
Cytat(marcinpl87 @ 13.02.2010, 02:23:49 ) *
witam, wlepiłem funkcję stream_set_timeout (nie wiem czy w dobrym miejscu) i co kawałek kodu dodałem echo 1 2 3 4 5 6 żebym wiedział w którym momencie skrypt się zatrzymał. Cały ten kod który poniżej wklejam jest wywoływany w pętli wiele razy:

Najpierw wypadało trochę poczytać z podanego linka, no i warto by zerknąć w przykłady poniżej.
Wiedział byś wtedy jak to stosować.

  1. if ($pinghandle = fsockopen($host, 80, $errno, $errstr, 30)) {
  2. @fputs( $pinghandle, $httpReq );
  3.  
  4. stream_set_timeout($pinghandle, 2);
  5. $info = stream_get_meta_data($pinghandle);
  6.  
  7. while (!feof($pinghandle) && (!$info['timed_out'])) {
  8. $pingresponse = @fgets( $pinghandle, 128 );
  9. $info = stream_get_meta_data($pinghandle);
  10. }
  11. @fclose( $pinghandle );
  12. }

To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.