Prima di proseguire...
Potrebbe interessarti la nostra collezione di esercizi C risolti?
Alcuni giorni fa avevo pubblicato una versione di un server di chat in php con i socket. Oggi pubblico una versione migliorata. Che al contrario dell’altra non rallenta la CPU, in quanto si ferma fin quando non si connette un nuovo client o vengono ricevuti nuovi dei messaggi.
ecco il codice:
<?php /************************************************************ copyright claudio cardinale 2004-2011! tutti i diritti reservati contatti : [email protected](o http://www.thecsea.it) versione : 1.0.0 data : 21/02/2011 18:01 *************************************************************/ class Server{ //proprieta private private $indirizzo = ""; private $porta = ""; private $sock = ""; private $clienti = array(); private $i = 0; //costruttore public function __construct($indirizzo, $porta){ $this->indirizzo = $indirizzo; $this->porta = $porta; print "avvio server in corso...\n"; set_time_limit(0); ob_implicit_flush(); $this->sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("socket_create() fallito: motivo: " . socket_strerror($this->sock) . "\n"); $ret = @socket_bind($this->sock, $this->indirizzo, $this->porta) or die("socket_bind() fallito: motivo: " . socket_strerror($ret) . "\n"); $ret = @socket_listen($this->sock, 5) or die("socket_listen() fallito: motivo: " . socket_strerror($ret) . "\n"); $ret = @socket_set_nonblock($this->sock) or die("socket_set_nonblock() fallito: motivo: " . socket_strerror($ret) . "\n"); $this->ciclo(); } //distruttore public function __destruct(){ socket_close($this->sock); foreach($this->clienti as $key=>$value) $this->disconnetti($key); } //metodi privati //ciclo principale private function ciclo(){ print "server avviato...\n"; $var = null; $var2 = null; for(;;){ //controllo cambiamenti $read = array_merge(array($this->sock),$this->clienti); socket_select($read,$var,$var2,null); //aggiunta clienti if(($key=array_search($this->sock,$read))!==false){ unset($read[$key]); $this->aggiungi(); } //chat if($read!==false) $this->chat($read); } } //aggiunta clienti private function aggiungi(){ //controllo nuovi clienti if($buf = @socket_accept($this->sock)){ //aggiunta cliente alla lista $this->clienti[$this->i] = $buf; //stampa e controllo se il cliente è connesso correttamete $msg = "\nBenvenuto in chat...\nscrivere quit per uscire...\n"; if($this->scrivi($buf, $msg)===false){ if($this->disconnetti($this->i)) print "errore con il cliente ".($this->i+1)." (in scrittura) -> disconnesso correttamente\n"; else print "errore con il cliente ".($this->i+1)." (in scrittura) -> impossibile disconnetterlo\n"; return false; } //ritorno $this->i++; print "cliente ".$this->i." aggiunto\n"; return true; } return false; } //richiamo metodi per chat private function chat($read){ //lettura clienti foreach($read as $key1=>$value1){ $ret = $this->leggi($value1); //key corrispondente nell'array clienti $key_o = array_search($value1, $this->clienti); //uscita if(trim($ret)=="quit") if($this->disconnetti($key_o)) print "cliente ".($key_o+1)." disconesso correttamente\n"; else print "errore con cliente ".($key_o+1)." (in disconnessione)\n"; //stampa sui clienti else if($ret){ foreach($this->clienti as $key2=>$value2) if($key_o!=$key2 && $this->scrivi($value2, $ret)===false) if($this->disconnetti($key2)) print "errore con il cliente ".($key2+1)." (in scrittura) -> disconnesso correttamente\n"; else print "errore con il cliente ".($key2+1)." (in scrittura) -> impossibile disconnetterlo\n"; //errore in lettura }else if($this->disconnetti($key_o)) print "errore con il cliente ".($key_o+1)." (in lettura) -> disconnesso correttamente\n"; else print "errore con il cliente ".($key_o+1)." (in lettura) -> impossibile disconnetterlo\n"; } return true; } //lettura private function leggi($sock){ return @socket_read($sock, 2048, PHP_NORMAL_READ); } //scrittura private function scrivi($sock, $mex){ return @socket_write($sock, $mex, strlen ($mex)); } //disconnessione cliente private function disconnetti($chiave){ if(@socket_close($this->clienti[$chiave])===false) return false; unset($this->clienti[$chiave]); return true; } } $server1 = new Server("127.0.0.1","9000"); $server1 = 0; ?>
In pratica invece di fare la socket_select solo sui socket dei clients la faccio anche sul socket principale, controllando poi con un if se ci sono stati cambiamenti nel socket principale. Se ci sono stati elimino il socket dal vettore read, in modo da lasciarlo con i soli socket dei clients, in seguito aggiungo i clients. Infine eseguo normalmente il metodo chat(se ci sono nuovi messaggi), come prima con l’unica differenza che il vettore read glielo passo come parametro, dato che è già stato calcolato.
N.B. è stato fatto anche un’altro miglioramento: nel caso in cui la la lettura restituisce un valore nullo o falso il client viene disconnesso
P.S. una versione leggermente modificata di questo codice è stata usata per creare un videogioco multiplayer
nuova versione server di chat in php con i socket by cardinale claudio is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Pingback: server di chat in php con i socket « blog thecsea.it