2010-10-22 6 views
6

J'ai testé l'écoute de socket PHP, et a rencontré le problème mentionné ci-dessus. Mon écouteur de test fonctionne autrement, mais si un client se déconnecte sans le dire au serveur, le script se lance dans une boucle infinie jusqu'à ce qu'un nouveau client se connecte. Le problème semble être sur la ligne $ready = socket_select($read, $write = NULL, $except = NULL, $tv_sec = NULL); car il devrait s'arrêter pour attendre les connexions ici, mais à la place il saute l'attente et court directement à travers la boucle.Comment détecter la déconnexion du client sur l'écouteur de socket PHP?

Des pointeurs seraient appréciés.

code:

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

penser à une meilleure conception de code – Svisstack

+0

@Svisstack En général, je ne paie pas beaucoup d'attention au code de test, puisque je vais faire une ré-écriture structurée complète si je commence à développer davantage. – onik

+0

S'il vous plaît, j'ai le même problème, comment pouvez-vous le résoudre? Vous avez fait if ($ data === FALSE), Mon problème est que le client est déconnecté (quand je déconnecte internet) mais je n'ai pas de chatnged_sockets? :( –

Répondre

5

J'ai trouvé le problème, il me manquait un socket_close() du bloc "Client déconnecté". Ainsi, le bloc est correct:

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

Utilisez get_last_error() pour vérifier cela.

+0

104: Connexion réinitialisée par l'homologue, mais comment fermer correctement le socket droit? – onik

+0

ce n'est pas un opcode pour cela? Connexion fermée? Essayez de simuler cela et vérifier quel opcode a été retourné par cette fonction dans ce cas et faire pour cela – Svisstack

+0

J'ai exécuté le script sur mon serveur et je me suis connecté à lui en utilisant SocketTest.Quand je déconnecte le client le serveur donne le code d'erreur 104. Code utilisé: '$ errorcode = socket_last_error(); $ errormsg = socket_strerror ($ errorcode); ("Erreur: (". $ Errorcode. ")". $ Errormsg. "\ N"); ' – onik