Un web server si può vedere come l’unione funzionale di due differenti applicazioni: in effetti, grazie alla presenza di un server composto da hardware e software di base possiamo, attraverso un particolare strato software, ricevere o inviare informazioni sulla rete.
Con sempre maggiore incisività si stanno diffondendo applicazioni che richiedono servizi remoti perché garantiscono scalabilità e manutenibilità con significativi risparmi in termini economici (vedi figura 2). In effetti, in questo contesto diverse schede che gestiscono differenti servizi possono scambiarsi tra loro informazioni per meglio gestire la singola applicazione: ogni scheda utilizza un microcontrollore per comunicare, grazie alla presenza di una libreria software di rete, con i dispositivi presenti nella rete.
Una libreria software è in grado sicuramente di semplificare il processo di progettazione delle applicazioni in rete, magari ricorrendo a un web server. In effetti, le possibilità sono diverse, basti pensare all’AVR Web Server (figura 1) che comprende un server completo con supporto TCP/IP su interfaccia Ethernet. Include inoltre il supporto per l’invio di posta elettronica e il software per la configurazione automatica del server web della rete.
IL WEB SERVER
Un server è, di fatto, una scheda hardware che ospita uno strato software per gestire l’intera risorsa. Un server può benissimo essere costituito da un PC o da una schedina hardware con un microcontrollore, AVR o Arduino. Di solito un web server ospita un sistema operativo Windows-like o, nella maggior parte dei casi, Linux, anche se è anche possibile trovare server con sistemi operativi custom o moduli software che utilizzano direttamente le risorse hardware senza la necessità di alcuna mediazione tra le differenti funzionalità. È chiaro che con un sistema operativo più evoluto, come Linux, è possibile sfruttare gestioni più avanzate della rete o di alcune funzionalità di scheda. In effetti, per via della presenza di un sistema operativo tradizionale come Linux, è pensabile configurare e impostare il nostro server per differenti scopi: da un tradizionale web server – inclusa la possibilità di elaborare e inviare al PC pagine web – fino a un database server, ossia quando si ha la necessità di gestire dati che utilizzati da un sito Internet o da un programma, passando per un SMTP (servizio utilizzato per gestire la posta elettronica). Non solo, in un tradizionale web server si presume che la risorsa venga utilizzata non da un solo utente ma da più persone. Per un servizio di questo tipo si ha la necessità di offrire un sistema che possa garantire connessioni ad alta velocità allo scopo di permettere un accesso veloce e costante ai dati del server stesso. Detto questo, è anche necessario, allo scopo di visualizzare le informazioni contenute all’interno del server, offrire un browser, ossia un’applicazione che permette di accedere al server sfruttando il protocollo HTTP. Il web server è un servizio, ossia un programma sempre attivo presente sul server, che ha come scopo principale elaborare richieste HTTP (pagine web) e restituire risposte all’utente. Il web server di tipo tradizionale deve essere configurato dall’amministratore del server stesso attraverso indicazioni precise e chiare, per mezzo di un programma specifico, su come si deve comportare e a quali richieste deve rispondere. In realtà, un web server di tipo embedded può anche presentare differenti caratteristiche e offrire un semplice strato software, configurabile in modo one shot, allo start-up dell’intero sistema senza alcuna possibilità di modifiche dinamiche.
WEBDUINO
Webduino è una libreria Arduino-based finalizzata alla gestione di un web server ed è stato sviluppato originariamente per un’altra applicazione. La libreria è espandibile perché è possibile inserire anche la gestione per consentire una connessione protetta. Webduino è rilasciato sotto licenza MIT e consente a tutti il suo riutilizzo. Ricordiamo che Arduino è una piattaforma di prototipazione elettronica open-source che si basa su hardware e software flessibili e facili da utilizzare. Le diverse piattaforme basate su Arduino sono in grado di interagire con l’ambiente attraverso sensori e possono gestire, per mezzo di attuatori, luci o motori. Il microprocessore sulle schede, del tipo Atmel AVR ATMega, è programmabile utilizzando il linguaggio di programmazione Arduino (basato su Wiring) e l’ambiente di sviluppo Arduino. Tutte le informazioni sui progetti e sui differenti software di sviluppo disponibili si possono trovare sul sito ufficiale del progetto [1]. Per utilizzare la libreria web server per Arduino, la Webduino, è necessario inserire il file WebServer.h nella cartella hardware/libraries/webduino o nel folder libraries per Arduino 0017 (a questo proposito in [2] si può trovare una breve guida). In caso di una configurazione non corretta verrà probabilmente generato l’errore “WebServer.h not found”. Per utilizzare correttamente la libreria è necessario modificare alcuni parametri presenti in libreria. In ogni modo, per prima cosa è necessario inserire il numero del MAC della scheda di rete (il MAC number è differente per ogni scheda presente sul nostro network), impostando la costante mac[], così
static uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
Con il passo successivo è necessario impostare l’indirizzo Internet della nostra scheda di rete:
static uint8_t ip[] = { 192, 168, 1, 64 };
A questo punto non ci rimane altro che impostare una istanza del nostro web server associando anche l’indirizzamento per le nostre pagine; con il parametro “/” tutte le pagine saranno poste alla base del server.
#define PREFIX “/“ WebServer webserver(PREFIX, 80);
Come ultimo passo è necessario definire le diverse funzioni presenti all’interno del nostro framework di lavoro, ossia helloCmd(), setup() e loop(). Attraverso la funzione setup() si provvede a inizializzare la connessione Ethernet e si predispone il nostro web server a ricevere e a gestire le connessioni in entrata e uscita (listato 1).
void setup() { /* initialize the Ethernet adapter */ Ethernet.begin(mac, ip); /* setup our default command that will be run when the user accesses * the root page on the server */ webserver.setDefaultCommand(&helloCmd); /* run the same command if you try to load /index.html, a common * default page name */ webserver.addCommand(“index.html”, &helloCmd); /* start the webserver */ webserver.begin(); }
Listato 1 – Inizializzazione del servizio |
Al contrario, la funzione loop() è chiamata dal web server per verificare se ci sono richieste in entrata alla nostra applicazione (listato 2).
void loop() { char buff[64]; int len = 64; /* process incoming connections one at a time forever */ webserver.processConnection(buff, &len); }
Listato – 2 ciclo di controllo delle richieste |
Per ultimo, helloCmd() ci permette di gestire la nostra vera applicazione. In effetti, a ogni richiesta in ingresso per mezzo del protocollo HTTP, la nostra applicazione provvederà a inviare un messaggio di “Hello World” per mezzo dell’HTML (listato 3).
void helloCmd(WebServer &server, WebServer::ConnectionType type, char *, bool) { /* this line sends the standard “we’re all OK” headers back to the browser */ server.httpSuccess(); /* if we’re handling a GET or POST, we can output our data here. For a HEAD request, we just stop after outputting headers. */ if (type != WebServer::HEAD) { /* this defines some HTML text in read-only memory aka PROGMEM. * This is needed to avoid having the string copied to our limited * amount of RAM. */ P(helloMsg) = “<h1>Hello, World!</h1>”; /* this is a special form of print that outputs from PROGMEM */ server.printP(helloMsg); } }
Listato 3 – La gesione del WebServer |
WEBDUINO CON AUTENTICAZIONE
Se volessimo implementare una procedura di autenticazione la soluzione veloce consisterà, sempre basandosi sulla libreria ufficiale del web server, nel modificare e aggiungere una classe derivata dalla classe web server: una modifica presente su Kithouse. La nuova classe dovrà assicurare l’autenticazione di ogni accesso ereditando tutta la libreria originale modificando la parte “private” della classe originale facendola diventare “protected”. La nuova funzione dovrà gestire la username e la password del sito web, ossia con
WebServerAuth(const char* user, const char* passwd, const char *urlPrefix, int port)
Lo strato di software presente sul target dovrà confrontare la stringa ricevuta con quella presente in memoria rappresentata in Base64. In effetti, con la procedura basic authentication, quando il browser invia un comando (GET) al web server del tipo:
GET /admin/index.html HTTP/1.0 Host: 192.168.0.100
Il web server dovrà rispondere con una richiesta di autenticazione del tipo:
HTTP/1.0 401 Authorization Required ... www-Authenticate: Basic realm=”webduino” Content-Type: text/html
Successivamente, il browser richiederà, in modo specifico, la username e la password all’utente che chiede il servizio. Una volta ricevuta la stringa di autenticazione, questa sarà codificata in base64 dal web server, rinnovando quindi la richiesta precedentemente inviata, con un reply, inserendo la username e password codificata precedentemente ricevuta:
GET /admin/index.html HTTP/1.0 Host: 192.168.0.100 Authorization: Basic YWRtaW46cGFzc3dvcmQ=
La stringa
“YWRtaW46cGFzc3dvcmQ=”
è la codifica in base64 di “username: password” (in questo caso specifico “admin:password”). Il codice si trova nel file con estensione .zip scaricabile dal sito della rivista. L’archivio contiene il file EncodeBase64.h, contenente il codice per la codifica Base64, la WebServerAuth.h, contenente la classe derivata e WebServer.h che contiene la classe webduino originale.
WEB SERVER CON ETHERNET SHIELD
Un’altra possibilità è quella di ricorrere a una scheda Ethernet Shield. In effetti, l’Arduino Ethernet Shield permette ad Arduino di connettersi al mondo Internet attraverso il funzionamento del drive W5100 WIZnet ethernet chip. Il chip offre una WIZnet (IP) in grado di assicurare uno stack di rete in àmbito TCP e UDP, supportando fino a quattro connessioni socket simultanee. Grazie a questo è possibile, per Arduino, usufruire di Internet per scrivere applicazioni ludiche e di lavoro. La Ethernet Shield (figure 3 e 4) si connette alla scheda Arduino per mezzo delle wire-wrap: in questo modo si mantiene intatto il layout dei pin permettendo di sovrapporre un altro Shield. Questa applicazione utilizza la libreria Ethernet indicata in [3]. La scheda dispone di un connettore standard del tipo RJ-45 con un trasformatore di linea integrato con PoE abilitato. Nell’ultima versione si è aggiunto uno slot micro-SD utile per memorizzare eventuali file dalla rete. Non solo, la scheda risulta anche compatibile con diverse configurazioni di Arduino, incluso Arduino Mega (con la libreria Ethernet). La funzionalità microSD card reader è accessibile tramite la libreria SD, Pin 4. Non solo, questa versione assicura anche la presenza di un reset controller allo scopo di garantire una corretta gestione del reset in fase di accessione del modulo W5100 Ethernet. Le revisioni precedenti di questo Shield non risultano con la variante Mega e devono essere resettate manualmente dopo l’accensione. La scheda dispone di diversi LED molto utili in fase di diagnosi (tabella 1). Una possibile implementazione di un web server per questa particolare configurazione è mostrata al listato 4.
/* Web Server A simple web server that shows the value of the analog input pins. using an Arduino Wiznet Ethernet shield. Circuit: * Ethernet shield attached to pins 10, 11, 12, 13 * Analog inputs attached to pins A0 through A5 (optional) */ #include <SPI.h> #include <Ethernet.h> // Enter a MAC address and IP address for your controller below. // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; byte ip[] = { 192,168,1, 177 }; // Initialize the Ethernet server library // with the IP address and port you want to use // (port 80 is default for HTTP): Server server(80); void setup() { // start the Ethernet connection and the server: Ethernet.begin(mac, ip); server.begin(); } void loop() { // listen for incoming clients Client client = server.available(); if (client) { // an http request ends with a blank line boolean currentLineIsBlank = true; while (client.connected()) { if (client.available()) { char c = client.read(); // if you’ve gotten to the end of the line (received a newline // character) and the line is blank, the http request has ended, // so you can send a reply if (c == ‘\n’ && currentLineIsBlank) { // send a standard http response header client.println(“HTTP/1.1 200 OK”); client.println(“Content-Type: text/html”); client.println(); // output the value of each analog input pin for (int analogChannel = 0; analogChannel < 6; analogChannel++) { client.print(“analog input “); client.print(analogChannel); client.print(“ is “); client.print(analogRead(analogChannel)); client.println(“<br />”); } break; } if (c == ‘\n’) { // you’re starting a new line currentLineIsBlank = true; } else if (c != ‘\r’) { // you’ve gotten a character on the current line currentLineIsBlank = false; } } } // give the web browser time to receive the data delay(1); // close the connection: client.stop(); } }
Listato 4 – semplice web server con Ethernet Shield |