Pagina 1 di 9 1 2 3 ... ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 88
  1. #1

    [Pillola] Socket, Server e Clients

    Volevo fare un regalo di natale

    Prima di iniziare leggetevi però gli articoli di fabio sulle socket altrimenti potrebbe mancarvi qualcosa :P

    http://freephp.html.it/articoli/view_articolo.asp?id=76
    http://freephp.html.it/articoli/view...olo.asp?id=112

    ---

    Cosa sono le socket?
    Sono quel sistema di trasmissione dei dati usato ad esempio nelle reti o su internet, tramite di esse potete contattare un'altro pc e inviargli o ricevere dei dati che poi possono essere analizzati.

    Le socket sono un mondo immenso dove non finirete MAI di immaginare
    Potete fare le cose più strane e divertenti, e sopratutto potete sviluppare POTENTI server scritti in PHP! Certo non potranno essere usati per reggere carichi eccessivi, ma vi voglio fare un'esempio:
    Immaginate che nella ditta in cui lavorate si stia sviluppando un protocollo di comunicazione compresso, e che essendo in svuluppo deve essere testato per vedere l'efficenza, il consumo di banda, il consumo di processore e altro ancora, immaginate che per farlo avete poco tempo, quindi non potete ad esempio usare come linguaggio il C o il C++ perché entrerebberò in ballo troppi fattori esterni e quindi lo sviluppo del protocollo sarebbe estremamente lento. La soluzione ideale sarebbe un linguaggio di script, perl? python? ma se sapete programmare con php, perché dover usre un'altro linguaggio? ebbene con php è possibile sviluppare i vostri server e sviluppare codice di un certo tipo!

    Per quanto riguarda le socket ci occuperemo soltanto delle socket del modulo esterno del php e non del sistema integrato delle socket in php, perché è molto più lento del modulo.

    Per chi programma in C\C++ ed ha già usato le socket sotto i sistemi *nix noterà che sono praticamente uguali

    Allora, facciamo un'esempio stupido, mettiamo che dovete scaricare un file dal web. Per farlo ci sono 3 modi, uno tramite le funzioni file di php, uno tramite le funzioni interne per le socket di php (che non tratteremo) ed infine tramite le socket del modulo.

    Con il primo metodo molto semplicemente

    codice:
    <?php
      $fp = fopen('test.html', 'wb+t');
      fwrite($fp, implode('', file('http://forum.html.it'));
      fclose($fp);
    ?>
    andiamo analizzando questo codice:
    - La prima riga si occupa di aprire il file test.html, e di crearlo se non esiste, in modalità di scrittura in modalità binaria con il supporto per la conversione del carattere di fine linea
    - La seconda linea si occupa di scrivere il file che abbiamo scaricato dal web (ne riparliamo nello specifico in seguito)
    - La terza chiude il file

    ok, smontiamo la seconda linea nei vari comandi:
    * file: questo comando supporta i cosidetti stream, come le funzioni interne di php. Questo vuol dire che posso mettere http, ftp e gli altri stream supportati internamente da php e in automatico mi restituirà il contenuto apposito. Ovvero a livello pratico oltre ad a leggere i file in locale posso leggere i file in remoto. Restituisce un'array dove per ogni elemento vi sta una linea, quindi molto comodo se dovete analizzare linea per linea, ma nel nostro caso a noi ci interessa "implodere" il file in un'unica riga per poterlo scrivere

    * implode: si occupa appunto di implodere un'array in un'unica stringa, e come elemento per unire i vari elementi dell'array e il primo parametro di implode, nel nostro caso specifico implode senza nessun carattere di separazione

    * fwrite: semplicemente scrive il contenuto della stringa che implode gli ha restituito.

    Questo era il primo metodo, ma ora passiamo al secondo metodo, quello più interessante che vi mostrerà MOLTE vie ^^ :P

    codice:
    <?php
      // Il file da scaricare
      $file = 'index.html';
      
      // Impostiamo dove si deve connettere
      $host = "www.google.it";
      
      // La porta a cui connettersi
      $port = 80;
      
      // Creiamo la socket (Una socket basata su IPv4, Socket Stream [ovvero un sistema di comunicazione con il controllo dell'errore] ed infine SOL_TCP gli specifica di usare il layer di comunicazione TCP
      $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
      
      // Dice a php di connettersi a HOST:PORT usando la socket creata in precedenza
      socket_connect($socket, $host, $port);
      
      // Prepariamo il contenuto da inviare
      $header_send = '';
      $header_send .= "GET /{$file} HTTP/1.0\n";
      $header_send .= "HOST: {$host}:{$port}\n";
      $header_send .= "\n";
      
      // Inviamo i dati
      socket_write($socket, $header_send);
      
      // Inzializziamo la variabile che conterra' i dati del buffer
      $buffer = '';
      
      // Legge i dati dalla sockeet a blocchi di 512 byte mettendoli dentro la variabile $tmpdata. Se socket_read restituisce FALSE, vuol dire che la comunciazione si è chiusa
      while (($tmpdata = socket_read($socket, 512)) != FALSE) {
        
        // Aggiungo i dati al buffer
        $buffer .= $tmpdata;
      }
      
      // Il protocollo HTTP 1.0 è composto da due sezioni separate da un duplice invio. La prima sezione sono le informazioni sul file ricevuto, la seconda è il contenuto
      $tmp = explode("\r\n\r\n", $buffer);
      
      // Estraggo gli headers
      $headers = array_shift($tmp);
      
      // Il contenuto poteva contenere a sua volta dei duplici invii, quindi per evitare di perdere dati o di averli malformati reimplodiamo l'array da cui abbiamo tolto gli headers
      $content = implode("\r\n\r\n", $tmp);
      
      // A questo punto mettiamo tutto dentro un file e abbiamo scritto il nostro "downloader" :)
      $fp = fopen(basename($file), "wb+t");
      fwrite($fp, $content);
      fclose($fp);
      
    ?>
    può sembrare complicato ma in realtà non lo è!
    Innanzi tutto all'inizio definiamo 3 variabili:
    - file
    - host
    - port

    Ovvero il file da scaricare, l'indirizzo ed infine la porta del server web a cui vogliamo connetterci per scaricare il file. Come esempio li ho definito www.google.it, porta 80 e come file index.html, ovviamente potete mettere qualunque cosa, anche file binari (ovvero eseguibili, compressi, immagini e altro ancora)

    Fatto questo dobbiamo creare la risorsa per poter gestire le socket! Ovvero dobbiamo dire al php di prepararci una socket che usi IPv4 (ovvero un sistema di comuncazione basato sul riferimento tramite un IP a 4 cifre), che utilizzi un sistema di comunicazione basato su uno STREAM affidabile, ovvero che controlla che i pacchetti inviati giungono a destinazione correttamente e simili ed infine gli diciamo di usare il TCP! Dalla combinazione IPv4, Stream, TCP deriva appunto il nome TCP/IP.

    Fatto questo diciamo al sistema di connettersi al server usando la socket appena creata. Noi qui non stiamo eseguendo alcun tipo di controllo ma potrebbe benissimo succedere che il server sià down e quindi vi sia errore, o che ad esempio il sistema ha allocato troppe socket e non ne possa allocare più.

    Dopo che php si è connesso al server che ci interessa prepariamo una semplice richiesta da inviare al server web per poter ricevere il file! Per l'esattezza diciamo al server web:
    - Che stiamo eseguendo una richiesta in GET (ovvero niente parametri passati tramite form o affini)
    - Che vogliamo leggere il file $file
    - Che stiamo usanto il protocollo 1.0 (c'è anche 1.1 ma richiede altri parametri che a noi non interessano)
    - Ed infine diciamo al server web che tra i siti che hosta, per quanto riguarda il file, si deve riferire all'host (in questo caso) www.google.it - Per quanto riguarda la comprensione di questo vi rimando al manuale di apache sui Virtual Host, comunque, se vogliamo dare una spiegazione veloce e semplice, i virtual host vi permettono di tenere più siti sulla stessa macchina! Il parametro HOST appunto dice al web server quale host utilizzare, e questo viene inviato dai browser ai server web appunto per poter ricevere le corrette informazioni.

    Preparati gli header li inviamo al server web usando socket_write. A questa funzione passiamo la socket da usare e i dati da inviare. Come parametro opzionale c'è anche la lunghezza dei dati da inviare, ma se non specificato invia TUTTI i dati contenuti nel buffer.

    Dopo che li abbiamo inviati stiamo in attesa di ricevere i dati fin quando la comunicazione non viene chiusa dall'altra parte.
    Nel ciclo while leggiamo i dati dalla socket a blocchi di 512 byte per volta e li aggiungiamo al nostro BUFFER.

    Dopo aver ricevuto tutti i dati chiudiamo la socket e passiamo all'analisi di questi

    La versione 1.0 (la 1.1 è leggermente diversa nella struttura) è formata da 2 parti principali:
    - Headers
    - Body

    La sezione Headers contiene tutte le informazioni sul file che abbiamo ricevuto! I mime-type, la dimensione, i tipi di file autorizzati, se il file esiste oppure è sotto autenticazione o altro ancora, o ancora i cookie ed altro.

    La sezione body contiene il vero e proprio file!

    Queste sezioni sono divise da un separatore formato da un doppio invio. Nel codice usiamo array_shift che restituisce il primo elemento di un'array e poi lo elimina dall'array stesso e poi utilizziamo implolde! Perché utilizzare implode? se nel file vi fosse un doppio invio succederebbe che con explode leggeremmo dall'inizio fino a quello spezzone, e non va bene ^^ in questo modo ricomponiamo il tutto senza problemi

    Alla fine scriviamo il file tramite le normalissime funzioni per la scrittura

    Come potete vedere è tutto abbastanza semplice, basta capire il meccanismo base!

    Arrivati a questo punto vi consiglio di interrompere la lettura della pillola e di chiarirvi le idee guardando il manuale e i commenti del manuale!

    http://www.php.net/socket_create
    http://www.php.net/socket_connect
    http://www.php.net/socket_read
    http://www.php.net/socket_write
    http://www.php.net/socket_close

    e di passaggio, dato che li abbiamo utilizzati
    http://www.php.net/file
    http://www.php.net/array_shift
    http://www.php.net/implode
    http://www.php.net/explode

    Ok, fino a questo punto abbiamo spiegato come utilizzare in maniera BASILARE le socket, ma ora passiamo alle cose più serie.
    Mettiamo che dovete sviluppare un server per la chat tramite php e telnet.

    Cosa deve fare il server?

    1° Inizializzarsi
    2° Mettersi in ascolto sulla porta 9999 (che sarà quella che useremo per fare il telnet)
    3° Attendere qualcuno che si connetta
    4° Autenticare chi si connette
    5° Introdurre l'utente appena connesso all'interno della chat

    quindi in pratica deve gestire:
    - L'autenticazione
    - La comunicazione

    Occupiamoci della prima.
    Innanzi tutto non è possibile entrare usando un nickname di qualcuno che già è dentro con quel nick ed inoltre ci sono i nick registrati.
    Quindi se l'utente X inserisce il nick Y il server deve chiedere la pass e controllare che sia valida. Per una questione di semplicità l'accoppiata username|password sarà scritta in un file di testo.
    Quindi il nostro file conterrà
    codice:
    daniele_dll|cicciobello
    gm|sonomod
    guidoz|valeria
    Come seconda cosa il server deve appunto permettere la chat (altrimenti che chat sarebbe )
    Quindi ogni volta che l'utente invia un messaggio questo deve essere inviato a tutti gli altri connessi! Ovviamente al messaggio andra anteposto il nick di chi lo invia

    Adesso iniziamo a scrivere il codice.
    Dobbiamo come prima cosa creare la configurazione del server stesso...quindi
    codice:
    <?php
    	$_CONFIG = array(
    		'host'				=> '0.0.0.0',
    		'port'					=> 9999,
    		'max_users'		=> 15,
    	);
    Nella configurazione abbiamo inserito l'ip sul quale bindarsi (un computer può avere più ip, ad esempio può avere l'ip di localhost, quindi 127.0.0.1, l'ip della rete interna, quindi, ad esempio, 10.0.0.1, ed infine l'ip su internet, quindi 80.231.34.51). Usando l'ip 0.0.0.0 gli viene detto di accettare le richieste di connessione da tutti gli ip disponibili nella macchina! Se ad esempio volessimo evitare che dall'esterno si possano connettere persone senza voler usare un firewall possiamo semplicemente inserire l'ip di localhost ovvero 127.0.0.1 e potremo connetterci SOLO noi dal nostro pc!
    Il secondo parametro contiene la porta alla quale connettersi, nel nostro caso sarà la 9999. Ovviamente su questa porta non devono essere in ascolto altri server senno riceveremo errori!

    Inizializziamo alcune variabili
    codice:
    	$_CLIENTS_INFO = array();
    	$_CLIENTS_SOCK = array();
    	$_CLIENTS_NICK = array();
    	
    	$_REGLIST = array();
    	
    	define("STATE_CONNECTED", 0);
    	define("STATE_WAITPASS", 1);
    	define("STATE_CANCHAT", 2);
    Queste variabili conterranno le informazioni sui client e le informazioni sulle socket, ed un'array aggiuntivo conterrà la lista dei nickname in modo da velocizzare la ricerca dei nickname in uso quando qualcuno si collega. L'ultimo array contiene la lista degli utenti registrati
    Il blocco di define servono a definire gli stati di un utente

    continua...

  2. #2
    Adesso il server deve creare la socket e mettersi in ascolto, quindi
    codice:
    	// Creiamo la socket
    	$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    	
    	// Controlliamo se ha dato errore o meno
    	if ($socket === FALSE) {
    		
    		// Se si il programma muore restituendo l'errore
    		die("Errore durante la creazione della socket!\n" . socket_strerror(socket_last_error()) . "[" . socket_last_error() . "]\n");
    	}
    	
    	// Impostiamo la socket come non blocking
    	socket_set_nonblock($socket);
    	
    	// Impostiamo la socket come riusabile
    	socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
    	
    	// Bindiamo la socket
    	$ris = socket_bind($socket, $_CONFIG['host'], $_CONFIG['port']);
    	if ($ris === FALSE) {
    		die("Impossibile impostare la socket!\n" . socket_strerror(socket_last_error()) . "[" . socket_last_error() . "]\n");
    	}
    	
    	// Mettiamo in ascolto la socket
    	$ris = socket_listen($socket);
    	if ($ris === FALSE) {
    		die("Impossibile mettersi in ascolto sulla porta {$_CONFIG['host']}:{$_CONFIG['port']}!\n" . socket_strerror(socket_last_error()) . "[" . socket_last_error() . "]\n");
    	}
    
    	// Leggiamo la lista degli utenti registrati e la inseriamo nell'array
    	$tmparr = file("userlist.usr");
    	while (list(, $value) = each($tmparr)) {
    		list($nick, $pass) = explode('|', $value);
    		$_REGLIST[$nick] = array(
    			'nick'		=> $nick,
    			'pass'		=> $pass
    		);
    	}
    In questa parte di codice creiamo una socket TCP/IP, la impostiamo in modalità NON-BLOCKING, ovvero il programma continuerà a lavorare e i comandi come socket_read e socket_write restituiranno SEMPRE false perché non attenderanno l'esecuzione del comando che potrebbe riuscire come non potrebbe riuscire, però questo ci permette di eseguire altre operazioni nel frattempo senza bloccare il programma e rallentare pesantemente il sistema operativo.
    Dopo di ciò impostiamo la socket in modalità REUSABILE, dopo di che diciamo che IP e PORTA deve usare la socket! Fatto ciò possiamo dire di mettersi in ascolto. In questo codice abbiamo inserito un minimo di gestione degli errori.

    Creiamo alcune funzioni che gestiranno l'invio dei dati a tutti gli utenti e l'avvertenza di quando uno si disconnette o entra
    codice:
    	// Funzione per scrivere nei socket
    	function sock_write(&$socket, $data, $return = TRUE) {
    
    		// Inizializza la variabile
    		$num = 0;
    		
    		// Attende che il numero di socket in cui si può scrivere è maggiore di zero
    		while ($num > 0) {
    		
    			// Crea un'array dove inserisce la socket in cui scrivere
    			$array = array($socket);
    
    			// Avvia il select sulla socket interessata
    			$num = socket_select($r = NULL, $array, $e = NULL, 0, 10);
    		}
    
    		// Controlla se alla fine della stringa ci sta il \n
    		if ($data{strlen($data)-1} != "\n" && $return) $data .= "\n";
    		
    		// Invia i dati
    		socket_write($socket, $data);
    	}
    	
    	// Funzione per gestire i nuovi utenti
    	function new_user($nick) {
    		global $_CLIENTS_INFO, $_CLIENTS_SOCK;
    		
    		// Cicla tutte le socket
    		foreach($_CLIENTS_SOCK as $socket) {
    
    			// Controlla se la socket indicata può chattare
    			if ($_CLIENTS_INFO[(int) $socket]['state'] != STATE_CANCHAT) continue;
    
    			// Invia il messagio
    			sock_write($socket, "User <{$nick}> connected!");
    		}
    	}
    	
    	// Gestione per la disconnessione di un utente
    	function quit_user(&$sock, $advise = TRUE) {
    		global $_CLIENTS_NICK, $_CLIENTS_INFO, $_CLIENTS_SOCK;
    
    		// Recupera il nick
    		$nick = $_CLIENTS_NICK[(int) $sock];
    		
    		// Controlla se deve avvisare
    		if ($advise) {
    			
    			// Cicla l'array delle socket
    			foreach($_CLIENTS_SOCK as $socket) {
    				
    				// Controlla che l'interessato possa chattare
    				if ($_CLIENTS_INFO[(int) $socket]['state'] != STATE_CANCHAT) continue;
    				
    				// Se si invio il messagio
    				sock_write($socket, "User <{$nick}> exit!");
    			}
    		}
    		
    		// Chiude la socket
    		socket_close($sock);
    		
    		// Scarica i vari riferimenti
    		unset($_CLIENTS_INFO[(int) $sock]);
    		unset($_CLIENTS_SOCK[(int) $sock]);
    		unset($_CLIENTS_NICK[(int) $sock]);
    
    		// Elimina la socket		
    		unset($sock);
    	}
    
    	// Gestione della chat
    	function chat_user($from_sock, $msg) {
    		global $_CLIENTS_INFO, $_CLIENTS_NICK, $_CLIENTS_SOCK;
    
    		// Estrae il nick
    		$from_nick = $_CLIENTS_NICK[(int) $from_sock];
    		
    		// Si cicla l'array delle socket
    		foreach($_CLIENTS_SOCK as $socket) {
    		
    			// Controlla che la socket selezionata non sia quella di provenienza e che possa chattare
    			if ($from_sock == $socket || $_CLIENTS_INFO[(int) $socket]['state'] != STATE_CANCHAT) continue;
    			
    			// Scrive il messagio
    			sock_write($socket, "<{$from_nick}> {$msg}");
    		}
    	}
    	
    	// Funzione per recuperare il nick dalla socket
    	function getsockfromnick($nick) {
    		global $_CLIENTS_NICK, $_CLIENTS_SOCK;
    		while(list($key, $value) = each($_CLIENTS_NICK)) {
    			if ($value == $nick) return $_CLIENTS_SOCK[$key];
    		}
    		return FALSE;
    	}
    	
    	// Funzione per controllare se un utente è registrato o meno
    	function user_is_regged($nick) {
    		global $_REGLIST;
    		if (isset($_REGLIST[$nick])) return TRUE;
    		return FALSE;
    	}
    	
    	// Funzione per controllare se user e pass corrispondono
    	function check_user($nick, $pass) {
    		global $_REGLIST;
    		if ($_REGLIST[$nick]['nick'] == $nick && $_REGLIST[$nick]['pass'] == $pass) return TRUE;
    		return FALSE;
    	}
    	
    	// Gestisce i messagi privati
    	function privatechat_user($from_sock, $to_nick, $msg) {
    		global $_CLIENTS_INFO, $_CLIENTS_NICK, $_CLIENTS_SOCK;
    		
    		// Estrae la socket dal nick
    		$socket = getsockfromnick($to_nick);
    		
    		// Estrae il nick dalla socket
    		$from_nick = $_CLIENTS_NICK[(int) $from_sock];
    		
    		// Controlla che il nick esista
    		if ($socket === FALSE) {
    		
    			// Se non esiste avverte che l'utente non c'è
    			sock_write($from_sock, "Unable to find <{$to_nick}>");
    		} else {
    			// Esiste, quindi controlla che chi deve ricever il messaggio può chattare
    			if ($_CLIENTS_INFO[(int) $socket]['state'] != STATE_CANCHAT) {
    				sock_write($from_sock, "Unable to find <{$to_nick}>");
    			}
    			
    			// Invia il messagio
    			sock_write($socket, "PRIVATE: <{$from_nick}> {$msg}");
    		}
    	}
    La prima funzione si occupa di scrivere nella socket le stringe che gli inviamo! E' importante quel while perché attende che sia possibile scrivere nella socket, se non lo facessimo potremmo avere errori a causa di grandi quantità di dati inviati alla socket remota.
    La seconda funzione si occupa di avvertire tutti gli utenti connesi che è entrato un nuovo utente, mentre la terza che un utente è uscito. Infine la quarta funzione si occupa di inviare i messaggi della chat ai vari utenti
    La quinta funzione controlla se un utente è registrato o meno, la sesta controlla la pass di accesso ed infine la settima gestisce i messaggi privati

    continua...

  3. #3
    Adesso che il server inizializza il tutto dobbiamo metterci in attesa di ricevere le informazioni
    codice:
    	// Crea un'array che conterrà la socket del server
    	$socket_array = array($socket);
    	
    	// Entra in loop infinito
    	while(1) {
    		
    		// Crea l'array delle socket da controllare
    		$tmparray = array_merge($socket_array, $_CLIENTS_SOCK);
    	  	
    	  	// Controlla se nelle socket ci sono dati disponibili
    		$num = socket_select($tmparray, $w = NULL, $e = NULL, 0, 10);
    	  	
    	  	// Se si
    		if ($num > 0) {
    		
    			// Cicla la lista delle socket con dati disponibili
    			foreach($tmparray as $sock) {
    			
    				// Controlla se la socket selezionata corrisponde alla socket del server
    				if ($sock === $socket) {
    				
    					// Controlla se il numero di utenti
    					if (count($_CLIENTS_SOCK) >= $_CONFIG['max_users']) {
    					
    						// Se si, accetta la socket
    						$new_sock = socket_accept($socket);
    
    						// Invia un messaggio
    						sock_write($new_sock, "Numero massimo di utenti raggiunto");
    						
    						// Chiude la socket
    						socket_close($new_sock);
    						
    						// Scarica la socket
    						unset($new_sock);
    						
    						// Continua il ciclo
    						continue;
    					}
    					
    					// Controlla se riesce ad accettare la socket
    					if ($new_sock = socket_accept($socket)) {
    
    						$tmpnum = (int) $new_sock;
    
    						// Estrae HOST e PORTA di provenienza
    						socket_getpeername($new_sock, $host, $port);
    						
    						// Inserisce le informazioni negli array
    						$_CLIENTS_SOCK[$tmpnum] = &$new_sock;
    						
    						$_CLIENTS_INFO[$tmpnum] = array(
    							'host' 	=> $host,
    							'port'		=> $port,
    							'key'		=> $tmpnum,
    							'buffer'	=> '',
    							'state'	=> STATE_CONNECTED,
    							'is_reg'	=> FALSE
    						);
    						
    						$_CLIENTS_NICK[$tmpnum] = '';
    						
    						// Invia il messaggio di entrata alla socket
    						sock_write($new_sock, "Nickname: ", FALSE);
    
    						// Elimina i riferimenti inutili
    						unset($tmpnum);
    						unset($new_sock);
    						
    					} else {
    					
    						// Errore, quindi muore
    						die("Errore durante l'accettazione di una socket!\n" . socket_strerror(socket_last_error()) . "[" . socket_last_error() . "]\n");
    					}
    				} else {
    				
    					// Legge i dati dalla socket
    					$buf = socket_read($sock, 512);
    					
    					// Controlla se la connessione è chiusa o ha dato errore
    					if ($buf == FALSE) {
    					
    						// Essendo chiusa fa disconnettere l'utente
    						quit_user($sock);
    						break;
    						
    					} elseif($buf == '') {
    						// Ha dato errore, quindi esce
    						die("Errore durante la ricezione dei dati\n" . socket_strerror(socket_last_error()) . "[" . socket_last_error() . "]\n");
    					}
    					
    					$tmpnum = (int) $sock;
    					
    					// Aggiunge i dati appena letti al buffer della socket
    					$_CLIENTS_INFO[$tmpnum]['buffer'] .= $buf;
    					
    					// Controlla se l'ultimo carattere è \n
    					if ($buf{strlen($buf)-1} == "\n") {
    					
    						// Se si controlla lo stato in cui si trova l'utente
    						switch($_CLIENTS_INFO[$tmpnum]['state']) {
    							case STATE_CONNECTED:	
    								
    								// Elimina gli ultimi caratteri inutili
    								$_CLIENTS_INFO[$tmpnum]['buffer'] = rtrim($_CLIENTS_INFO[$tmpnum]['buffer'], " \r\n");
    								
    								// Riceve il nick, controlla il suo contenuto! Non può contenere spazi.
    								if (strpos(' ', $_CLIENTS_INFO[$tmpnum]['buffer'])>0) {
    									sock_write($sock, "Il nickname non può contenere spazi!\nReinserisci il nickname: ", FALSE);
    									break;
    								}
    								
    								// Controlla se il nick non è già in uso
    								if (in_array($_CLIENTS_INFO[$tmpnum]['buffer'], $_CLIENTS_NICK)) {
    									sock_write($sock, "Nickname già in uso, scegline un'altro!\nReinserisci il nickname: ", FALSE);
    									break;
    								}
    								
    								// Se tutto va bene imposta il nick
    								$_CLIENTS_NICK[$tmpnum] = $_CLIENTS_INFO[$tmpnum]['buffer'];
    								
    								// Controlla se l'utente è registrato
    								if (user_is_regged($_CLIENTS_NICK[$tmpnum])) {
    									$_CLIENTS_INFO[$tmpnum]['state'] = STATE_WAITPASS;
    									sock_write($sock, "Questo nickname è registrato, invia la password!\nPassword: ", FALSE);
    									break;
    								}
    								
    								// Non e' registrato quindi annunzia del nuovo utente
    								new_user($_CLIENTS_NICK[$tmpnum]);
    								
    								// Imposta lo stato
    								$_CLIENTS_INFO[$tmpnum]['state'] = STATE_CANCHAT;
    								break;
    								
    							case STATE_WAITPASS:
    							
    								// Elimina i caratteri inutili
    								$_CLIENTS_INFO[$tmpnum]['buffer'] = rtrim($_CLIENTS_INFO[$tmpnum]['buffer'], " \r\n");
    
    								// Controlla che la password sia corretta
    								if (!check_user($_CLIENTS_NICK[$tmpnum], $_CLIENTS_INFO[$tmpnum]['buffer'])) {
    									sock_write($sock, "Password errata!\nBye Bye\n");
    									quit_user($sock, FALSE);
    									break;
    								}
    								
    								// Tutto ok, quindi annunzia il nuovo utente
    								new_user($_CLIENTS_NICK[$tmpnum]);
    								
    								// Imposta alcune informazioni
    								$_CLIENTS_INFO[$tmpnum]['state'] = STATE_CANCHAT;
    								$_CLIENTS_INFO[$tmpnum]['is_reg'] = TRUE;
    								break;
    								
    							case STATE_CANCHAT:
    							
    								// Controlla se l'utente sta chiedendo un messaggio privato
    								if (preg_match("/^\/PVT ?([^ ]+) (.+)/i", $_CLIENTS_INFO[$tmpnum]['buffer'], $tmparr)) {
    									privatechat_user($sock, $tmparr[1], $tmparr[2]);
    									break;
    								}
    								
    								// Controlla se sta chiedendo la disconnessione
    								if (preg_match("/^\/EXIT/i", $_CLIENTS_INFO[$tmpnum]['buffer'], $tmparr)) {
    									quit_user($sock);
    									break;
    								}
    								
    								// Controlla se sta chiedendo di uccidere il server (solo per i registrati)
    								if (preg_match("/^\/QUIT/i", $_CLIENTS_INFO[$tmpnum]['buffer'], $tmparr) && $_CLIENTS_INFO[$tmpnum]['is_reg']) {
    									chat_user($sock, "Chisura del server in corso");
    									echo "Chiusura del server in corso";
    									die();
    									break;
    								}
    								
    								// Dato che non è nessuno di questi, vuol dire che è chat ed invia il messaggio
    								chat_user($sock, $_CLIENTS_INFO[$tmpnum]['buffer']);
    								break;
    						}
    						
    						// Svuota il buffer
    						$_CLIENTS_INFO[$tmpnum]['buffer'] = '';
    					}
    				}
    			}
    		}
    	}
    ?>
    Credo che qui i commenti parlino da soli
    Comunque in parole povere fa questo:

    - Controlla le socket per vedere se ci sono eventi (dati in arrivo, richiesta di connessione)
    - Appena si verifica un evento controlla se è una richiesta di connessione o dati in arrivo
    - Se è una richiesta di connessione, controlla se il numero massimo di utenti non è stato raggiunto e se no aggiunge l'utente alla lista ed invia la richiesta per il nick
    - Se sono dati in arrivo, ci possono essere 3 situazioni in cui il server si può trovare!
    - Situazione APPENA CONNESSO, se succede questo vuol dire che stiamo aspettando il nickname da parte dell'utente, e lo abbiamo ricevuto! Quindi lo controlliamo e controlliamo se c'è un'utente registrato con quella password
    - Situazione ATTESA PASSWORD, dopo aver inviato il nick, solo per gli utenti registrati. Il programma controlla se l'utente ha inviato o meno la password corretta
    - Situazione PUO' CHATTARE, l'utente può inviare i comando o la normalissima chat
    - Inoltre se l'utente chiude la finestra del telnet in automatico viene detto agli altri utenti che un user si è disconnesso

    Il server supporta i comandi base come /EXIT (per disconnettersi) e /PVT user messagio (per mandare messagi privati)
    Se si è utenti registrati si ha a disposizione anche il comando /QUIT che serve a killare il server

    ok, qui mi fermo, anche perché devo andare a mangiare!
    Spero che il mio regalo di fine anno vi sia piaciuto
    Se incontrate errori di ortografia avvertite che correggo, se invece il server ha qualke malfunzionamento, chiedo perdono, ma l'ho scritto in un'ora e neanché (test, ideazione scrittura dei commenti\spiegazioni pillola compreso e)

    ciao a tutti ^^ se avete dubbi potete postare qui oppure sul mio forum

    bauz!

  4. #4
    Voglio essere il primo dell'ultimo dell'anno a congratularmi per il lavoro.

    Pero' e' sulla fiducia, lo leggero' il prossimo anno.


    Il silenzio è spesso la cosa migliore. Pensa ... è gratis.

  5. #5
    ok...ho finito ^^

    domattina metto sul mio sito internet a disposizione il codice sorgente

    ciaooo

  6. #6
    Originariamente inviato da piero.mac
    Voglio essere il primo dell'ultimo dell'anno a congratularmi per il lavoro.

    Pero' e' sulla fiducia, lo leggero' il prossimo anno.

    anche xche sono 27000 caratteri e passa ^^

    prima o poi posto il librone che sto lentamente scrivendo sulle socket ^^

    xora è 40kappa ^^ e sono +/- all'inizio

  7. #7
    voglio essere l'ultimo del vecchio anno a sbavare

  8. #8
    Originariamente inviato da }gu|do[z]{®©
    voglio essere l'ultimo del vecchio anno a sbavare
    :quote:

    vuol dire che per il nuovo anno non sbavi?

  9. #9
    Utente di HTML.it L'avatar di Pasco
    Registrato dal
    Apr 2002
    Messaggi
    1,559
    Complimenti

    mi hanno sempre incuriosito le socket , ma non mi sono mai interessato più di tanto
    PyFanatics

  10. #10

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.