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");
}
}
}
?>
myśleć o lepszej konstrukcji kodu – Svisstack
@Svisstack Zazwyczaj nie zwracamy dużą uwagę na kodzie testowym, ponieważ zrobię pełną strukturalną przepisać jeśli zacznę dalszy rozwój. – onik
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? :( –