tesinaSockets e DatagramSockets (498927 byte)
Transcript
tesinaSockets e DatagramSockets (498927 byte)
Tesina esame ‘Programmazione di Sistemi Mobile’ realizzata da Roberto Giuliani matricola 633688 Sockets e DatagramSocket Windows Phone prevede un’interfaccia di programmazione per garantire agli sviluppatori di creare applicazioni che possono comunicare con i servizi internet e altre applicazioni remote usando le sockets. Esempi che usano le sockets per comunicare sono FTP, email, sistemi di chat e multimedia streaming (YouTube). Usando le sockets nelle applicazioni Windows Phone si è in grado di creare ricche applicazioni client che possono comunicare tramite Trasmission Control Protocol (TCP) o User Datagram Protocol (UDP). Una socket non è altro che un’interfaccia software che si posiziona tra i livelli del modello ISO-OSI del trasporto e applicativo, la quale permette ad un processo di comunicare conoscendo sia la rispettiva porta, che il rispettivo indirizzo. Vengono definite dallo strato di rete tramite un indirizzo, il quale è combinazione dell’Internet Protocol (IP) address ed il numero di porta. Windows Phone prevede un’interfaccia di programmazione necessaria a creare e usare le sockets TCP e UDP. E’ possibile selezionare quale tipo si preferisce utilizzare in relazione alle caratteristiche che l’applicazione richiede. Il diagramma mostra una vista delle operazioni che vengono eseguite durante una sessione di comunicazione tra un’applicazione client e una service. Le sockets sono generalmente usate quando non vi è un alto livello di API o altre astrazioni per lo scenario, quando è coinvolto un protocollo personalizzato, quando vi è la necessità di un protocollo bidirezionale o quando ha senso per ridurre al minimo il sovraccarico di ogni scambio. Nel mondo delle sockets, lo scambio di informazioni può avvenire in due modi, come pacchetto/messaggio singolo o come un canale continuo (detto stream). Loro sono chiamati datagram sockets e stream sockets e sono entrambi supportati attraverso le API WinRT. La suddivisione della scelta avviene in relazione al protocollo che si implementa e che si utilizza. Sta al programmatore quindi decidere in base alle caratteristiche del rispettivo applicativo. In questa tesina si è deciso di sviluppare il concetto di Datagram Sockets. Inoltre WinRT supporta anche le forme di scambio tra il protocollo WebSocket, una tecnologia originariamente creata per web browsers e web servers ma che ha preso notevole sviluppo in scopi di utilizzo generale all’interno delle app. Tutte le informazioni possono essere trovare nelle classi che corrispondono all’API Windows.Networking.Sockets. Datagram Sockets Nella terminologia delle sockets, un datagram corrisponde ad un unico messaggio completo, nella quale sono contenute sia le informazioni relative alla comunicazione che ai dati che vogliono essere trasferiti da una socket all’altra. Senza avviare a priori una connessione ed utilizzando lo standard User Datagram Protocol (UDP). Tale standard è considerato come una forma di scambio semplice, senza stato, unidirezionale ed orientato alla transazione. Ha una minima intestazione rilasciata nel messaggio (di pochi bit) e non prevende la ritrasmissione del datagramma in caso di non ricezione o perdita, per queste ragioni non può garantire una corretta e sicura ricezione (non vi è quindi la presenza di Acknowledge). Inoltre viene utilizzato dove il controllo degli errori e la loro correzione non sono necessari o dove questo processo viene svolto in una parte superiore del modello ISO-OSI come per esempio nello strato applicativo, quindi dall’applicazione stessa. Per esempio sarà compito dell’applicazione assicurarsi che i dati ricevuti corrispondano a quelli veramente concordati e richiesti. E non farlo svolgere al livello di traporto, quali per esempio il protocollo TCP. Nel momento in cui i messaggi non sono quelli aspettati si procede alla richiesta di rinvio (sempre a livello applicativo). In poche parole, UDP permette di minimizzare i ritardi, una volta ricevuto il messaggio dello strato superiore esso lo ‘impacchetta’ e lo invio immediatamente, rendendo le latenze approssimativamente vicine allo zero. I protocolli di alto livello come Real-time Transport Protocol RTP e il Real Time Streaming Protocol RTSP sono costruiti su UDP. Possono essere aggiunti degli attributi che consentono un utilizzo migliore di questo protocollo. Come, per esempio, un tempo in millisecondi che verrà decrementato fino alla ricezione del messaggio, nel momento in cui tale valore raggiunge la soglia dello zero si ipotizzerà che la richiesta è andata persa e quindi sarà rinviato il pacchetto. L’implementazione di una socket a lato client potrebbe seguire la seguente sintassi: Socket socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); Dove vengono indicate le seguente proprietà: - AddressFamily.InterNetwork: la socket utilizzerà lo schema di indirizzamento IP versione 4 per risolvere un indirizzo. Avviene quando l’oggetto socket si connette al terminare scelto. - SocketType.Dgram: indica che la socket supporta pacchetti che corrispondono a datagrammi (o messaggi). - ProtocolType.Udp: fa riferimento al protocollo UDP (User Datagram Protocol) Un’applicazione Windows Store lavora con questo tipo di trasporto – sia lato client che lato server – usando la classe DatagramSocket, nella quale, inizializzando una specifica connessione, attivi un listener che attende i messaggi. Rimanendo in ascolto nell’evento messagereceived. Quando i dati arrivano, l’handler riceve un oggetto DatagramSocketMessageReceived-EventArgs. Questo contiene le proprietà localAddress e remoteAddress, entrambi dei quali sono un oggetto Windows.Networking.HostName che contiene un indirizzo IP, un display name e un paio di altri bits. Gli argomenti dell’evento contengono anche una stringa che indica il remotePort. Più importanti sono i due metodi dalla quale si estraggono i dati. Uno è getDataStream, che restituisce un IInputStream attraverso il quale si possono leggere sequenzialmente dei byte dal network remoto di destinazione. L’altro è getDataReader che restituisce un oggetto Windows.Storage.Streams.DataReader. Questa è un’astrazione ad alto livello costruita su IInputStream che aiuta a leggere direttamente specifici dati. Chiaramente, se si conosce la struttura dei dati, che ci si aspetta di ricevere nel messaggio, usando il DataReader si opererà direttamente il tipo di conversione si vuole. Ovviamente, si prende qualunque tipo di informazione da una socket, e si necessita di collegarla a qualcosa. A questo proposito DatagramSocket include un paio di metodi per utilizzare e gestire la connessione: - connectAsync: Inizia un’operazione di connessione dando un oggetto HostName ed il nome al servizio (oppure una stringa per la porta UDP) della destinazione remota. Questo viene utilizzato per creare una connessione mono-direzionale dal client al server. - Un’altra form di connectAsync prende un oggetto Windows.Networking.EndpointPair che specifica il nome dell’host e del service sia per il terminale locale che per quello remoto. Questo viene utilizzato per creare una connessione bidirezionale client/server, dove il terminale locale implica una chiamata a bindEndpointAsync vista nel seguito. - bindEndpointAsync: Per una connessione monodirezionale – che solo ascolta ma non invia i dati sulla sockets – questo metodo lega un terminale locale dando un HostName e un nome o porta del service. Legando il nome del service da se stesso può essere fatto con bindServiceNameAsync. - joinMulticastGroup: Da un Hostname, connesso alla Datagram socket a un gruppo multicast. - Close: Permette di terminare la connessione e concludere qualunque operazione. Nota che qualunque socket viene data, essa può essere connessa ad un qualunque numero di terminale – si può invocare connectAsync più volte, unire molteplici gruppi di multicast e legare molteplici terminali locali con bindEndpointAsync e bindServiceNameAsync. A differenza del metodo close() chiude tutto una volta! Una volta che la socket ha una o più connessioni, le informazioni della connessione possono essere recuperate con la proprietà DatagramSocket.information. Nota anche che il metodo statico DatagramSocket.getEndpointPairsAsync prevede (come un risultato async) un vettore di oggetti EndpointPair disponibili per un hostname remoto e un service name. I dati di controllo possono anche essere impostati attraverso la proprietà DatagramSocket.control, come l’oggetto DatagramSocketControl con le proprietà qualityOfService e outputUnicastHopLimit. Tutto questo lavoro, ovviamente, è solo il preambolo dell’invio dei dati sulla connessione socket. Questo viene effettuato attraverso la proprietà del DatagramSocket.outputStream, un IOutputStream nel quale tu puoi scrivere i dati che interessano usando i metodi writeAsync e SendToAsync. Questo invierà i dati su ogni connessione entro la socket. Alternativamente tu puoi utilizzare una delle variazione di getOutStreamAsync per specificare un EndpointPair o Hostname/port nel quale inviare i dati. Il risultato di entrambi queste operazioni async è ancora un IOutputStream. E in tutti i casi si può creare un oggetto DataWriter di alto livello attorno allo stream: Interessante aspetto è quando si presenta un errore sulla connessione socket, dove si può passare il numero di tale errore al metodo getStatus dell’oggetto SocketError e riprendere un valore SocketErrorStatus più completo. Magari per risolvere errori imprevisti. Nel seguito vengono implementati due metodi (Send e Receive) di utilizzo delle sockets da parte del client Questo metodo chiamato Send(…) riceve in ingresso come parametri il nome del server, il numero della porta della socket di destinazione e i dati che si desidera trasferire. E come valore di ritorno ottengo una stringa che contiene un messaggio di errore se l’invio non è avvenuto correttamente, mentre una segnalazione di TimeOut se è avvenuto correttamente e siamo in attesa della risposta a lato server. Da sottolineare in tale struttura è la creazione dell’oggetto SocketAsyncEventArgs, esso deriva dalla classe corrispondente ed è parte di un insieme di miglioramenti che può essere utilizzato come modello asincrono alternativo da applicazioni socket specializzate con elevate prestazioni. Successivamente vengono impostate alcune delle sue proprietà, quali il buffer dei dati e la sua dimensione. Anche in questo caso evidenziamo il metodo RemoteEndPoint il quale ottiene o imposta l’endPoint remoto per l’operazione asincrona. Il metodo conclusivo, SendToAsync(…), corrisponde al vero e proprio invio del pacchetto da parte della Socket creata in precedenza. Per ricevere la notifica di completamente è necessario creare un metodo di callback che implementa il delegato EventHandler<SocketAsyncEventArgs> e collegarlo all’evento SocketAsyncEventArgs.Completed, come si vede nella struttura sopra. Differente invece la parte in ricezione svolta sempre a lato client, nella quale viene implementato il metodo Receive(…) che restituisce come risultato una stringa contenente o l’errore avvenuto durante la fase di ricezione dei dati oppure i dati stessi ricevuti dal server. Anche in questo caso viene inizializzato un oggetto di tipo SocketAsyncEventArgs che con la proprietà garantita dal metodo RemoteEndPoint permette di rimanere in ascolto in attesa di un messaggio da qualunque indirizzo IP esterno che conosca la porta della Socket interessata. Per poi impostare il buffer ed inserirci i dati ricevuti dal server tramite il metodo ReceiveFromAsync(…). Solo una volta conclusa l’intera comunicazione è possibile chiudere la socket.