2010-10-22 202 views
6

我一直在測試PHP套接字偵聽,並遇到上述問題。我的測試監聽器工作正常,但如果客戶端在不告訴服務器的情況下斷開連接,則腳本將進入無限循環,直到新客戶端連接。這個問題似乎在$ready = socket_select($read, $write = NULL, $except = NULL, $tv_sec = NULL);上,因爲它應該停止等待這裏的連接,而是跳過等待並直接在循環中運行。如何檢測PHP套接字監聽器上的客戶端連接斷開?

任何指針,將不勝感激。

代碼:

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

想想更好的代碼設計 – Svisstack 2010-10-22 11:15:21

+0

@Svisstack通常我不重視測試代碼,因爲如果我開始進一步發展,我會做一個完整的結構化重寫。 – onik 2010-10-22 11:18:00

+0

請問我有同樣的問題,你怎麼解決它? 你做了if($ data === FALSE),我的問題是雖然客戶端斷開(當我斷開互聯網),但我沒有任何chatnged_sockets? :( – 2014-08-28 01:43:12

回答

5

找出問題所在,我錯過了「Client disconnected」塊中的socket_close()。所以,正確的塊是:

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

使用get_last_error()進行檢查。

+0

104:連接重置由對端,但如何正確關閉正確的插座? – onik 2010-10-22 11:23:37

+0

這是沒有操作碼?連接關閉?嘗試模擬此並檢查此操作返回此操作的代碼和操作定義 – Svisstack 2010-10-22 11:26:40

+0

我在我的服務器上運行腳本並使用SocketTest連接到它,當我斷開客戶端時,服務器給出錯誤代碼104.使用的代碼:'$ errorcode = socket_last_error(); $ errormsg = socket_strerror($ errorcode); die (「Error:(」。$ errorcode。「)」。$ errormsg。「\ n」);' – onik 2010-10-22 11:53:32

相關問題