2010-10-22 21 views
6

He estado probando la escucha del socket PHP, y me encontré con el problema antes mencionado. Mi oyente de prueba funciona bien, pero si un cliente se desconecta sin avisarle al servidor, el script entra en un bucle infinito hasta que un nuevo cliente se conecta. El problema parece estar en la línea $ready = socket_select($read, $write = NULL, $except = NULL, $tv_sec = NULL);, ya que debería detenerse para esperar aquí las conexiones, pero en su lugar se saltea la espera y se ejecuta directamente a través del ciclo.¿Cómo detectar la desconexión del cliente en el escucha de socket PHP?

Cualquier puntero sería apreciado.

Código:

#!/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

pensar en un mejor diseño de código – Svisstack

+0

@Svisstack Por lo general no prestan mucha atención a código de prueba, ya que voy a hacer una reescritura completa estructurada si comienzo a desarrollar aún más. – onik

+0

Por favor, tengo el mismo problema, ¿cómo podrías resolverlo? Has hecho if ($ data === FALSE), Mi problema es que el cliente se desconectó (cuando desconecté internet) pero no tengo ningún chatnged_sockets? :( –

Respuesta

5

Descubrí cuál era el problema, me faltaba un socket_close() del bloque "Cliente desconectado". Por lo que el bloque correcto es:

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

Uso get_last_error() para comprobar esto.

+0

104: Restablecimiento de la conexión por pares, pero ¿cómo cierro correctamente el socket correcto? – onik

+0

este no es un código de operación? Conexión cerrada? Intente simular esto y compruebe qué código de operación devolvió esta función en este caso y hágalo. define. – Svisstack

+0

Ejecuté la secuencia de comandos en mi servidor y me conecté a ella usando SocketTest. Cuando desconecto el cliente, el servidor da el código de error 104. Código utilizado: '$ errorcode = socket_last_error(); $ errormsg = socket_strerror ($ errorcode); die ("Error: (". $ Errorcode. ")". $ Errormsg. "\ N"); ' – onik

Cuestiones relacionadas