Networking: HTTP

Valuta questo articolo 0 Voti

Autori: Lorenzo Maiorfi e Gianluca Ruta

Il protocollo applicativo più utilizzato (non in termini di traffico, ma sicuramente di EndPoint disponibili) su Internet è senza dubbio quello utilizzato dalle applicazioni "browser" per fruire dei contenuti pubblicati dai siti web: il protocollo HTTP. Per essere più precisi, il protocollo HTTP (e le sue successive evoluzioni, quali il WebDAV) si occupa solo di descrivere il modello richiesta/risposta attraverso il quale un client può richiedere ed ottenere un qualche tipo di informazione veicolata da un canale di comunicazione basato su TCP/IP. Quando la risposta veicola, all'interno del corpo dei propri pacchetti HTTP, un testo codificato secondo un determinato linguaggio come avviene quando si richiede una pagina HTML, il browser si occupa, oltre che dello "scaricamento" della pagina, anche della sua visualizzazione, attraverso l'utilizzo di un motore di "rendering" implementato all'interno dell'applicazione browser stessa.

Quello che ci interessa in questo contesto è capire come poter effettuare delle richieste HTTP all'interno di un dispositivo embedded che utilizzi il .NET Micro Framework, al fine di utilizzare delle informazioni pubblicate all'interno di una Intranet o di Internet nel nostro firmware. E' opportuno premettere da subito che non dovremo cedere alla tentazione di provare a realizzare un browser web all'interno del nostro firmware, dal momento che la complessità di un motore di rendering che permetta la visualizzazione di contenuti HTML è al di sopra delle possibilità di questo tipo di dispositivi, o almeno lo è nei dispositivi che non siano dotati di un vero e proprio sistema operativo.

Ciò nonostante, la tendenza ad utilizzare servizi esposti su Internet mediante quella che prende il nome di API RESTful rende questo approccio estremamente conveniente. Come esempio, vediamo cosa serve per realizzare un semplice firmware che effettui una ricerca su Twitter, il noto portale community costruito intorno alla pubblicazione di brevi messaggi di testo. In particolare utilizzeremo l'API RESTful di Twitter per ottenere, in formato XML (più in dettaglio in formato AtomPub) una lista di messaggi pubblicati che riportano il termine "netmf".

Il codice relativo all'esempio in questione è riportato nel frammento di codice che segue:

public class Program

{

    public static void Main()

    {

        // Creazione di una nuova richiesta http

        HttpWebRequest request = HttpWebRequest.Create(

                "http://search.twitter.com/search.atom?q=netmf") as HttpWebRequest;


        // Invio della richiesta

        HttpWebResponse response = request.GetResponse() as HttpWebResponse;


        // Uso uno stream reader per leggere la risposta

        using (StreamReader sr = new StreamReader(response.GetResponseStream()))

        {

            // Se lo status code http è 200 (ok)

            if (response.StatusCode == HttpStatusCode.OK)

            {

                // Debug del contenuto della risposta

                Debug.Print(sr.ReadToEnd());

            }

            else

            {

                // Debug dello status code ottenuto (ad es. 404 Not Found)

                Debug.Print(response.StatusDescription);

            }

        }

    }

}

E' opportuno notare che le funzionalità di client HTTP sono completamente incapsulate nelle classi HttpWebRequest e HttpWebResponse, che si occupano in maniera completamente trasparente sia della gestione dei socket sottostanti che delle richieste DNS necessarie. Anche in questo caso la lettura del contenuto della risposta proveniente dal server avviene tramite uno StreamReader. Per chi conosce il protocollo HTTP, vale inoltre la pena di notare che la gestione delle informazioni "fuori-banda" tipicamente veicolate dagli header è interamente implementata dalle classi in questione, che per gli header più importanti espongono proprietà specifiche, come ad esempio StatusCode di HttpWebResponse, che permette di rilevare l'esito di una richiesta HTTP.

Il test pratico è davvero elementare: basta eseguire in debug il firmware sopra analizzato e osservare la risposta alla ricerca su Twitter (in formato XML) nella finestra di Debug.

Anche nel caso delle comunicazioni HTTP, vediamo invece ora come è possibile implementare un server Web embedded con il .NET Micro Framework. In particolare ci proponiamo di realizzare un semplice firmware in grado di pubblicare sul web (Internet o rete locale, dipendentemente dalla configurazione della rete in cui è inserito il dispositivo) informazioni relative all'ambiente fisico circostante. Facendo riferimento ancora alla scheda TahoeII di Device Solutions, utilizzeremo il controller del touch-screen built-in, denominato TSC2046, per rilevare la temperatura ambientale.

Una volta avviato il dispositivo, non dovremo far altro che digitare nella barra degli indirizzi di un browser  l'indirizzo http://<indirizzo>:8080/status (nel nostro esempio http://192.168.0.237:8080/status). Se è tutto ben configurato otterremo un risultato simile a quello illustrato nella figura seguente:

Il codice relativo al server web appena illustrato è riportato nel frammento di codice seguente:

public class Program

{

     public static void Main()

     {

         // Creo un server in ascolto di richieste http

         HttpListener server = new HttpListener("http",8080);


         // lo avvio...

         server.Start();


         while (true)

         {

             HttpListenerResponse response = null;

             HttpListenerContext context = null;


             try

             {

                 // Aspetto una richiesta http (questa chiamata è bloccante)

                 context = server.GetContext();

                 response = context.Response;


                HttpListenerRequest request = context.Request;


                 // Verifico che la richiesta fatta sia del tipo "http://<indirizzo>:8080/status"

                 if (request.RawUrl == "/status")

                 {

                     // Mando lo status code 200 (OK)

                     response.StatusCode = (int)HttpStatusCode.OK;


                     // Comunico al browser che il contenuto va visualizzato come html

                     response.ContentType = "text/html";


                     // Compongo la risposta...

                     using(StreamWriter sw=new StreamWriter(response.OutputStream))

                     {

                         string html = "<html><head><title>.NET MF Test Page</title></head>";

                         html += "<body><h1>Questo &#232; un server web realizzato con";

                         html += ".NET Micro Framework</h1>";

                         html += "<h2>";

                         html += "Qui la temperatura &#232; di " +

                              TahoeII.Tsc2046.ReadTemperature().ToString("F") + 

                             "&#186;C";

                         html += "</h2>";

                         html += "</body></html>";


                         sw.Write(html);

                     }

                 }

             }

             catch

             {

                 // Se ci sono stati problemi nella richiesta chiudo comunque il contesto...

                 if (context != null) context.Close();

             }

         }

     }

}

Come si può notare, le funzionalità relative all'implementazione del protocollo HTTP sono anche in questo caso completamente demandate ad una classe del framework, la HttpListener. Il codice si commenta da sé e l'unica cosa che vale la pena sottolineare è l'utilizzo della classe statica relativa al driver per la gestione del controller del Touch Screen, utilizzata in questo contesto per rilevare la temperatura che farà parte del documento HTML restituito al browser da cui è provenuta la richiesta.

 

WebServices

L'uso delle comunicazioni HTTP al fine di veicolare informazioni che non esprimano necessariamente elementi di interfaccia utente, come frammenti di markup HTML ad esempio, è diventato negli ultimi anni estremamente importante e diffuso, al punto da meritare un nome specifico: WebServices. L'argomento è sicuramente troppo esteso per essere trattato in questa sede, in cui saremmo in ogni caso interessati a coglierne soprattutto gli aspetti inerenti lo sviluppo di applicazioni embedded, ma vale la pena di sottolineare che nel .NET Micro Framework è stato implementato un completo stack di protocolli dedicati all'esposizione ed al consumo di webservices, secondo quanto previsto dallo standard DPWS (Device Profile Web Services). Tale standard, oltre a supportare gran parte delle tecnologie e dei protocolli utilizzati nei Web Services non espressamente rivolti all'uso embedded, aggiunge una serie di funzionalità specifiche, finalizzate per lo più alla costruzione di reti di dispositivi con funzionalità "mesh" quali "discovery", servizio con il quale un dispositivo può "annunciarsi" all'interno della rete o anche ricercarne altri compatibili con il tipo di interfaccia richiesto, o "eventing", con cui è possibile realizzare interfacce di comunicazione non più basate solo sul paradigma, tipicamente HTTP, richiesta/risposta, ma più ricche, in cui sia possibile utilizzare anche il pattern full-duplex per lo scambio dei messaggi. Se volete approfondire tale argomento, potete fare riferimento ai due progetti di esempio che illustrano l'utilizzo dello stack DPWS, denominati SimpleService e SimpleServiceClient , presenti all'interno del .NET Micro Framework SDK.