2010-10-22 12 views
6

Testowałem nasłuchiwanie w gnieździe PHP i wpadłem na wspomniany wcześniej problem. Mój słuchacz testowy działa inaczej, ale jeśli klient rozłącza się bez powiadomienia serwera, skrypt przechodzi do nieskończonej pętli, dopóki nowy klient się nie połączy. Problem wydaje się być na linii $ready = socket_select($read, $write = NULL, $except = NULL, $tv_sec = NULL);, ponieważ powinien przestać czekać na połączenia tutaj, ale zamiast tego pomija czekanie i biegnie prosto przez pętlę.Jak wykryć rozłączenie klienta w module nasłuchującym gniazda PHP?

Wszelkie wskazówki byłyby mile widziane.

Kod:

#!/usr/bin/php -q 
<?php 

$debug = true; 
function e($str) { 
    global $debug; 
    if($debug) { echo($str . "\n"); } 
} 

e("Starting..."); 
error_reporting(1); 
ini_set('display_errors', '1'); 

e("Creating master socket..."); 
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 
$max_clients = 10; 

e("Setting socket options..."); 
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1); 
e("Binding socket..."); 
socket_bind($socket, "192.168.1.38", 20000); 
e("Listening..."); 
socket_listen($socket, $max_clients); 

$clients = array('0' => array('socket' => $socket)); 

while(TRUE) { 
    e("Beginning of WHILE"); 
    $read[0] = $socket; 

    for($i=1; $i<count($clients)+1; ++$i) { 
     if($clients[$i] != NULL) { 
      $read[$i+1] = $clients[$i]['socket']; 
     } 
    } 

    e("Selecting socket..."); 
    $ready = socket_select($read, $write = NULL, $except = NULL, $tv_sec = NULL); 
    e("socket_select returned " . $ready); 
    e("If..."); 
    var_dump($socket); 
    var_dump($read); 
    if(in_array($socket, $read)) { 
     e("If OK"); 
     for($i=1; $i < $max_clients+1; ++$i) { 
      if(!isset($clients[$i])) { 
       e("Accepting connection..."); 
       $clients[$i]['socket'] = socket_accept($socket); 

       socket_getpeername($clients[$i]['socket'],$ip); 
       e("Peer: " . $ip); 
       $clients[$i]['ipaddr'] = $ip; 

       socket_write($clients[$i]['socket'], 'Welcome to my Custom Socket Server'."\r\n"); 
       socket_write($clients[$i]['socket'], 'There are '.(count($clients) - 1).' client(s) connected to this server.'."\r\n"); 

       echo 'New client connected: ' . $clients[$i]['ipaddr'] .' '; 
       break; 
      } elseif($i == $max_clients - 1) { 
       echo 'Too many Clients connected!'."\r\n"; 
      } 

      if(--$ready <= 0) { 
       continue; 
      } 
     } 
    } 

    e("For..."); 
    for($i=1; $i<$max_clients+1; ++$i) { 
     e("In..."); 
     if(in_array($clients[$i]['socket'], $read)) { 
      e("Reading data..."); 
      $data = @socket_read($clients[$i]['socket'], 1024, PHP_NORMAL_READ); 

      if($data === FALSE) { 
       unset($clients[$i]); 
       echo 'Client disconnected!',"\r\n"; 
       continue; 
      } 

      $data = trim($data); 

      if(!empty($data)) { 
       if($data == 'exit') { 
        socket_write($clients[$i]['socket'], 'Thanks for trying my Custom Socket Server, goodbye.'."\n"); 
        echo 'Client ',$i,' is exiting.',"\n"; 
        socket_close($clients[$i]['socket']); 
        unset($clients[$i]); 
        continue; 
       } 

       for($j=1; $j<$max_clients+1; ++$j) { 
        if(isset($clients[$j]['socket'])) { 
         if(($clients[$j]['socket'] != $clients[$i]['socket']) && ($clients[$j]['socket'] != $socket)) { 
          echo($clients[$i]['ipaddr'] . ' is sending a message!'."\r\n"); 
          socket_write($clients[$j]['socket'], '[' . $clients[$i]['ipaddr'] . '] says: ' . $data . "\r\n"); 
         } 
        } 
       } 
       break; 
      } 
     } 
    } 
    if($loops == 0) { 
     $firstloop = time(); 
     $loops++; 
    } else { 
     $loops++; 
     if((time() - $firstloop) >= 5 && $loops > 25) { 
      /*for($j=1; $j<$max_clients+1; ++$j) { 
       if(isset($clients[$j]['socket'])) { 
        if($clients[$j]['socket'] != $socket) { 
         echo('Server is looping, sending keepalive...'."\r\n"); 
         if(!socket_write($clients[$j]['socket'], '-KEEPALIVE-' . "\r\n")) { 
          echo 'Client ',$j,' not found, killing...',"\n"; 
          socket_close($clients[$j]['socket']); 
          unset($clients[$j]); 
          die("debug"); 
         } 
        } 
       } 
      }*/ 
      die("Looping started.\n"); 
     } 
    } 
} 
?> 
+0

myśleć o lepszej konstrukcji kodu – Svisstack

+0

@Svisstack Zazwyczaj nie zwracamy dużą uwagę na kodzie testowym, ponieważ zrobię pełną strukturalną przepisać jeśli zacznę dalszy rozwój. – onik

+0

Proszę, mam ten sam problem, jak mogłeś go rozwiązać? Zrobiłeś jeśli ($ data === FALSE), Mój problem polega na tym, że klient rozłączył się (kiedy odłączam Internet), ale nie mam żadnych chatnged_sockets? :( –

Odpowiedz

5

Dowiedziałem się, na czym polegał problem, brakowało mi socket_close() z bloku "Odłączony klient". Tak poprawny blok jest:

if($data === FALSE) { 
    socket_close($clients[$i]['socket']); 
    unset($clients[$i]); 
    echo 'Client disconnected!',"\r\n"; 
    continue; 
} 
2

Zastosowanie get_last_error() to sprawdzić.

+0

104: Połączenie resetowane przez peer, ale jak właściwie zamknąć właściwe gniazdo? – onik

+0

to nie jest kod operacyjny? Połączenie zamknięte? Spróbuj zasymulować to i sprawdź, jaki kod został zwrócony przez tę funkcję w tym przypadku i zrób to Zdefiniuj: – Svisstack

+0

Uruchomiłem skrypt na moim serwerze i podłączyłem go za pomocą SocketTest .. Po odłączeniu klienta serwer podaje kod błędu 104. Używany kod: '$ errorcode = socket_last_error(); $ errormsg = socket_strerror ($ errorcode); ("Błąd: (". $ Kod błędu. ")". $ Errormsg. "\ N"); ' – onik

Powiązane problemy