Quest'articolo è dedicato a tutti quelli che hanno le manine lunghe come me e nelle domeniche pomeriggio invece di lavorare spendono il proprio tempo a studiare come funzionano i software che giornalmente utilizziamo!
Era da tempo che ero curioso di capire come di preciso TCPServer e XINETD funzionassero!
Premetto che già un po conoscevo il funzionamento base di questi 2 applicativi per linux però se non si prova, non si può essere certi!
Qui farò le prove solo con TCPServer, comunque, sia TCPServer sia XINETD hanno un funzionamento abbastanza simile.
TCPServer e XINETD sono due utilissimi software che consentono di sviluppare, con una certa semplicità, software di rete: entrambi sono infatti un semplice ponte, un tramite, tra il client che effettua la richiesta ed il vostro applicativo.
In pratica:
Internet ----> Sistema Operativo ----> TCPServer\XINETD ----> Il vs. software
Mettiamo che TCPServer sia stato configurato per avviare il software chiamato XYZ quando arriva una richiesta di connessione all'indirizzo IP 0.0.0.0 (quindi tutti quelli disponibili) e alla porta 1234: nel momento in cui arriverà una richiesta TCPServer avvierà il software che avete indicato!
Prima di avviare il programma, in realtà, imposterà una serie di variabili di ambiente per poter fornire al software maggiori informazioni senza doverlo fare però attraverso la linea di comando o lo standard input: questo piccolo particolare, in realtà, è molto importante perché virtualmente qualsiasi software che lavora con dei dati in ingresso dallo standard input e restituisce i dati tramite lo standard output può essere utilizzato.
Ogni cosa che il client invierà sarà disponibile sullo standard input ed ogni che vorrete inviare dovrà essere inviata allo standard output.
Se ad esempio si volesse scrivere un server di rete che trasformi del testo in un altro usando TCPServer o XINETD e sed sarebbe possibile.
Per chiarirvi un po l'idea su cosa sono lo standard input e lo standard output e come si usano con php, date un occhio a:
http://www.phpfreaks.com/tutorials/86/0.php
http://www.phpbuilder.com/columns/darrell20000319.php3
Ho realizzato un piccolo script nel quale ogni volta che viene ricevuto il un carattere di ritorno a capo, questo viene reinviato al client inserendo come suffisso "### Echo:".
Lo script è veramente banale, in ogni caso, di seguito, il software è analizzato nel dettaglio
#!/usr/bin/php -q
Trattandosi di scripting con linux questa riga è fondamentale perché dice al sistema operativo che cosa va usato per interpretare ed eseguire il file stesso, in questo caso php
<?php // Definisco la configurazione // Definisco le costanti per lo standard INPUT e lo standard OUTPUT // Definisco alcune stringhe standard
Vengono definite alcune costanti tra cui lo standard input e lo standard output e delle stringhe utilizzate dopo.
Le costanti MSGS_BEGIN2 e MSGS_ECHO contenegono delle %s perché verranno utilizzate con sprintf.
Molto importante è notare che le due costanti STDIN e STDOUT non contengono una stringa ma bensi una risorsa! PHP ha riconosciuto che php://stdin e php://stdout non erano 2 stringhe qualsiasi ma bensi lo standard input e lo standard output e si è comportato di conseguenza
// Invio una stringa di riconoscimento
Invia i due messaggi di benvenuto al client inviando le stringe allo standard output. I messaggi sono definite nelle costanti di su.
Le due variabili $_ENV['TCPREMOTEIP'] e $_ENV['TCPREMOTEPORT'] le definisce TCPServer al momento della connessione
// Inizializzo il buffer $buffer = ''; // Raccolgo i dati
Inizializzo il buffer, ovvero imposto la variabile, e leggo un carattere per volta dallo stdin. Questo per evitare problemi, infatti non essendo una socket, ma un file non l'ho impostato sulla modalità non blocking.
Se avessi usato gli stream per gestire il tutto avrei potuto impostare la modalità non blocking e quindi leggere blocchi di dato maggiori. Se avessi messo 10 al posto di uno finche sullo standard input non ci sarebberò stati 10 byte a me non sarebbe ritornato nulla. Quindi, anche premendo invio, non sarebbe successo niente.
Invece in questo modo ogni volta che arriva un carattare viene processato.
// Controllo se il byte letto corrisponde all'invio if ($data != "\n") { // Se non corrisponde controlla la dimensione del buffer // Se la dimensione massima del buffer e' superata resetta // il buffer con il dato appena letto $buffer = $data; } else { // Se la dimensione massima non e' stata superata aggiunge // il dato al buffer attuale $buffer .= $data; }
A questo punto devo processare il byte ricevuto, quindi controllo se è un carattere di invio, ovvero se contiene uno \n o meno.
Se non contiene lo \n, quindi l'andata a capo processo se la stringa ha superato la lunghezza massima del buffer con un semplice if. Se il buffer è stato riempito tutto lo svuoto e lo riempo con il nuovo carattere, alrtimenti, se c'è ancora spazio, aggiungo il byte appena letto.
} else { // E' arrivato il momento di replicare i dati // quindi stampiamo il buffer e poi lo svuotiamo // Svuotiamo il buffer $buffer = ''; } } // --- Esecuzione terminata --- ?>
Se invece al programma arriva l'invio invia alla risorsa dello standard output la stringa che contiene il messaggio ripetuto e svuota il buffer. Come vedete anche qui uso sprintf per impostare il dato dentro la stringa.
Il programma poi termina e li potete fare quello che volete, tcpserver non termina il processo fin quando non è il processo stesso a morire quindi potete fare quello di cui avete bisogno
Di seguito il codice per intero.
#!/usr/bin/php -q <?php // Definisco la configurazione // Definisco le costanti per lo standard INPUT e lo standard OUTPUT // Definisco alcune stringhe standard // Invio una stringa di riconoscimento // Inizializzo il buffer $buffer = ''; // Raccolgo i dati // Controllo se il byte letto corrisponde all'invio if ($data != "\n") { // Se non corrisponde controlla la dimensione del buffer // Se la dimensione massima del buffer e' superata resetta // il buffer con il dato appena letto $buffer = $data; } else { // Se la dimensione massima non e' stata superata aggiunge // il dato al buffer attuale $buffer .= $data; } } else { // E' arrivato il momento di replicare i dati // quindi stampiamo il buffer e poi lo svuotiamo // Svuotiamo il buffer $buffer = ''; } } // --- Esecuzione terminata --- ?>
Utilizzando le funzioni per la gestione dei file in accoppiata allo stdin e stdout e questi applicativi è possibile scrivere svariati tipi di server! Ovviamente se avete dovete sviluppare soluzioni più avanzate e complesse non è la strada da seguire ma se non avete particolari necessità potrebbe essere una strada da seguire: e' possibile realizzare server di posta, server ftp, server web e via dicendo. E' importante comunque ricordarsi che questa tipologia di applicativi consuma più risorse rispetto ad una soluzione ad hoc!
Il pacchetto che contiene TCPServer si chiama uscpi-tcp ed è usatissimo con QMAIL, un buon server di posta elettronica, anche se per la sua infrastruttura è abbastanza pesante, mentre XINETD è standard in qualsiasi distribuzione, e sostituisce il vecchio INETD che eseguiva lo stesso dipo di operazioni.
Per aggiungere il vostro server a XINETD basta che creiate un file dentro la dir /etc/xinetd.d e li dentro aggiungiate una configurazione. Per maggiori info lanciate il comando:
man xinetd.conf
Vi mostrerà come scrivere un file di configurazione per xinetd per lanciare i vostri programmi
TCPServer invece non ha un man, per avere maggiori info guardate qui
http://cr.yp.to/ucspi-tcp/tcpserver.html
Per scaricare i vari sorgenti
http://cr.yp.to/ucspi-tcp.html
Per avere altre info sulle variabili di ambiente...
http://cr.yp.to/ucspi-tcp/environment.html
E' codice molto vecchio, scritto a inizio 2004, che non rispecchia la mia attuale metodologia di scrittura del codice, non rispecchia le mie attuali conoscenze e soprattutto potrebbe contenere codice che potrebbe non funzionare correttamente ad oggi.

Commenti recenti
42 settimane 4 giorni fa
42 settimane 4 giorni fa
50 settimane 3 giorni fa
1 anno 5 giorni fa
1 anno 5 giorni fa
1 anno 5 giorni fa
1 anno 21 settimane fa
1 anno 21 settimane fa
1 anno 24 settimane fa
1 anno 24 settimane fa