Summary: Si presentano i principali protocolli e strumenti per far comunicare tra loro applicazioni software e dispositivi diversi.
La comunicazione tra macchine diverse è strutturata secondo cinque strati:
Ogni host ha un indirizzo internet univoco in senso globale, usato da IP per instradare i messaggi. Esso è di 32 bit (in IPv4, e di 128 bit in IPv6, diventato standard nel 1996) e normalmente fornito in notazione "dotted-quad" (e.g. 157.138.204.250) o come nome di host (e.g. www.iuav.it). La traduzione da nomi a numeri puo' avvenire mediante il file /etc/hosts o mediante il database distribuito chiamato Domain Name Service (DNS). Ogni applicazione deve avere un numero di port (di 16 bit) univoco all'interno dell'host, usato da TCP per gestire la comunicazione da e verso l'applicazione. I numeri fino a IPPORT_RESERVED (tip. 1024) sono riservati per un accesso ai server di sistema (HTTP, FTP, etc.).
Un blocco di dati inviato da una applicazione si arricchisce di informazioni aggiuntive (header) mentre scende verso gli strati piu' bassi dei protocolli di comunicazione.
All'interno del TCP header, il sequence number tiene traccia dell'ordine dei pacchetti inviati (non piu' grandi di 64KB), in modo che in ricezione si possano individuare i pacchetti persi e ricostruire l'ordine corretto. Mediante il checksum il ricevente è in grado di rilevare errori di trasmissione. Il ricevente notifica la corretta ricezione mediante messaggi di risposta. Essendo questo protocollo basato sulla connessione di due nodi, tale connessione (virtuale) deve essere stabilita prima di iniziare la comunicazione. Il protocollo UDP (User Datagram Protocol) consente la comunicazione priva dell'overhead dovuto ai controlli di integrità e consistenza dei messaggi. Essenzialmente, UDP aggiunge ad IP soltanto la capacita' di indirizzare dei port. Nell'UDP header c'è anche un campo checksum, ma non è previsto l'acknowledgement di ricezione corretta. Il protocollo UDP non ha bisogno di una connessione stabilita prima della comunicazione. Il protocollo UDP, oltre ad avere minore overhead rispetto a TCP, è anche essenziale al supporto di certe attività. Si pensi ad esempio al programma ping, il quale verifica la qualità di una connessione. Esso può funzionare solo se ha la possibilita' di verificare la perdita eventuale di pacchetti.
Un processo server attende le eventuali connessioni di processi client. Quando la connessione viene stabilita, il server esegue dei compiti in base a quanto ricevuto dal client e poi, di solito, la connessione viene interrotta. La comunicazione tra client e server deve essere affidabile. La programmazione della comunicazione mediante TCP/IP viene di solito effettuata mediante l'interfaccia socket BSD, introdotta da UNIX 4.2BSD. E', di fatto, una forma di Inter-Process Communication che si aggiunge alle altre forme di comunicazione tra processi di UNIX (pipe, shared memory, signals, message queues, semaphores) con la peculiarità di consentire la comunicazione tra macchine diverse fornite di indirizzo IP.
| CLIENT | - | SERVER |
| conosce hostname e port number del server | - | ascolta il socket |
| richiede la connessione al server | → | accetta la connessione |
| crea un socket e lo usa per comunicare con il server | ← | ottiene un nuovo socket su un port differente |
| - | continua ad ascoltare il socket originario |
Il protocollo di trasmissione UDP realizza di fatto un modello di comunicazione di tipo message passing con ricezione bloccante e invio non bloccante. Quindi i due partner comunicano con una forma di rendez vous "lasco". E' demandato al programmatore il compito di assicurare la corretta ricezione dei messaggi (datagram) se essa è importante per l'applicazione.
Tra le core libraries di Processing, la Network consente di creare client e server.
In questo esempio la posizione del mouse sulla finestra
determina valori di ampiezza e frequenza che controllano
i parametri di un oscillatore server. Più correttamente,
si assume che ci sia un oscillatore con due server già
attivi: uno in ascolto sulla porta 5214
(frequenza) e uno in ascolto sulla porta
5215 (ampiezza). Il numero IP
127.0.0.1 indica localhost, o la medesima
macchina su cui sta girando il codice Processing.
import processing.net.*;
int portf = 5214;
int porta = 5215;
Client frequency, amplitude;
int val = 0;
void setup() {
size(200, 200);
frequency = new Client(this, "127.0.0.1", portf);
amplitude = new Client(this, "127.0.0.1", porta);
}
void draw() {
background(val);
frequency.write(str(mouseX));
frequency.write(';');
amplitude.write(str(height - mouseY));
amplitude.write(';');
}
Pure
Data mette a disposizione gli oggetti netsend e
netreceive per realizzare la comunicazione di
tipo client-server.
L'oggetto netreceive apre un socket di ricezione
TCP (stream) o UDP (datagram) su un port specificato come
argomento. Quando si usa TCP, l'outlet di destra restituisce
il numero di client che hanno aperto su questo socket la
connessione. La comunicazione via UDP si sceglie aggiungendo
un secondo argomento 1 a netsend e
netreceive.
E' frequente
oggigiorno l'utilizzazione di protocolli di rete per l'invio
di dati raccolti con sensori. Esempi di dispositivi che fanno
questo sono le macchine Kroonde e Toaster di La Kitchen,
azienda francese che ha purtroppo chiuso le proprie attività
di recente. Queste macchine si appoggiano a UDP per inviare i
dati raccolti dai sensori, e sono a disposizione dei
patch per Pure Data, basati su netreceive,
sono a disposizione.
Un oscillatore che risponde a richieste quali quelle
riportate in Esempio 1 è rappresentato in
Figura 1. Si noti come in Esempio 1 il valore numerico rappresentante la
posizione del mouse viene convertito in stringa nel momento
in cui esso viene inviato. Inoltre, viene inserito il
separatore ';' per consentire
l'estrazione dei numeri da parte di Pure Data.
![]() |
Si modifichino i client e server di Esempio 1 e Esempio 2 in maniera da realizzare una comunicazione bidirezionale. Per esempio, fare in modo che le consolle di Processing e Pure Data scrivano entrambe i valori scambiati di frequenza.
import processing.net.*;
int portf = 5214;
int porta = 5215;
int ports = 5204;
Client frequency, amplitude;
Server myServer;
int val = 0;
void setup() {
size(200, 200);
frequency = new Client(this, "127.0.0.1", portf);
amplitude = new Client(this, "127.0.0.1", porta);
myServer = new Server(this, ports);
}
void draw() {
background(val);
frequency.write(str(mouseX));
frequency.write(';');
amplitude.write(str(height - mouseY));
amplitude.write(';');
Client thisClient = myServer.available();
if (thisClient !=null) {
String whatClientSaid = thisClient.readString();
if (whatClientSaid != null) {
print(whatClientSaid);
}
}
}
![]() |
Il protocollo MIDI (Musical Instrument Digital Interface; IPA) è un protocollo di comunicazione tra dispositivi elettronici, introdotto dalle industrie degli strumenti musicali all'inizio degli anni '80 per garantire l'interoperabilità dei propri apparati. Il fatto che esso non si occupa di trasmettere segnali ma messaggi relativi ad eventi ha fatto sì che la sua diffusione sia stata ampia anche in ambito non strettamente musicale. Lo standard MIDI comprende sia il protocollo di comunicazione sia la definizione dell'interfaccia fisica. Questa trasmette alla velocità di 31,250 bit al secondo dei pacchetti costituiti da un bit di start (0), otto bit (un byte) di dati, un bit di stop (1). I messaggi scambiati sono relativi a eventi discreti (note-on, note-off, etc.) o processi che inviano flussi di valori (pitch bend, aftertouch, control change, etc.). Tutti questi messaggi appartengono a uno (o tutti) di 16 canali. Un byte di status, contenente canale e codice relativo al tipo di messaggio, precede uno o due byte di dati. Per le interazioni continue che ci si trova a dover trattare nell'interaction design, sono particolarmente utili i control change. Il MIDI ha avuto un notevole successo come standard industriale e, per molte applicazioni, funziona egregiamente ed ha un punto di forza nella sua semplicità. Tuttavia, ha gli svantaggi di una comunicazione seriale e a bassa velocità, nonché le limitazioni legate alla sua bassa espressività e all'origine nell'ambito degli strumenti musicali a tastiera.
In Pure Data, è disponibile una gamma di oggetti per la
gestione dei messaggi MIDI. La pagina di documentazione di
riferimento è riportata in Figura 3. Si vede,
ad esempio, che l'oggetto ctlin ha tre outlet che
forniscono, rispettivamente, il valore, il numero, e il canale
di un control change.
![]() |
Audio MIDI Setup che consente di impostare uno
Inter-Application Communication - IAC Driver o un
MIDI Network driver. Se abilitati, questi device
driver saranno poi selezionabili come input e output device
dalle preferences di Pure Data.
OpenSound Control - OSC è un protocollo di comunicazione che consente a diversi dispositivi elettronici e applicazioni di scambiarsi dati in tempo reale su un supporto di rete. E' stato sviluppato per superare le limitazioni di MIDI e per sfruttare le possibilità di TCP e UDP, consentendo al tempo stesso una semantica raffinata dei messaggi. Le caratteristiche principali di OSC sono:
/voices/synth1/osc1/modfreq) /voices/synth1/osc[1-4]/modfreq) /voice/3/freq, specificare come type tag un
singolo numero floating point, e il suo argomento può essere
261.62558. L'indirizzamento aperto di OSC consente a ogni
server di definire il proprio spazio di indirizzamento in
relazione alla propria organizzazione di servizi.
Un'ottima introduzione
a OSC si può scaricare, insieme a dettagliata
documentazione e a link alle realizzazioni software presso il
sito
ufficiale di OSC.
Per Processing esiste la libreria oscP5 che consente di produrre ed interpretare messaggi e bundle di OSC.
Si installi oscP5 per Processing e si provino gli esempi
della documentazione. In
particolare, si cerchi di comprendere la composizione e
decomposizione dei messaggi. Nell'esempio
oscP5plug è illustrato un meccanismo di
event-based
programming, secondo il quale è possibile
instradare messaggi con un determinato pattern di
indirizzo a un metodo specifico di una classe
(event handler).