====== Esercitazione 9: Pipe e socket====== Questa esercitazione si concentra su meccanismi di IPC. ==== Esercizio 1: Produttore e consumatore con pipe ==== Scrivere un programma C che implementi un processo produttore che genera N numeri casuali, li passa ad un processo consumatore usando una //pipe senza nome// e poi termina. Il consumatore deve stampare ciascun numero ricevuto sullo standard output e terminare a sua volta. ==== Esercizio 2: who_sort_cat ==== Scrivere un programma C che utilizzando //pipe senza nome// e la duplicazione di descrittori implementa il pipeline di shell bash:~$ who | sort | cat per stampare la lista di utenti connessi. Ogni comando deve girare in un processo diverso.\\ Elaborazione: Usare ''wc -l'' al posto di cat per avere il numero di connessioni. ==== Esercizio 3: Un server ed un client ==== Realizzare un processo server ed un processo client. I due processi intergiscono utilizzando due pipe con nome: //clientserver// e //clientp//. Il server crea la pipe clientserver (se non esiste), la apre e si mette in attesa di messaggi da parte del client. Ogni messaggio è costituito da un double. Per ogni messaggio ricevuto ''x'', il server calcola ''x*x'' e invia il risultato su //clientp//. La sequenza di messaggi termina quando il client chiude la pipe //clientserver//. Le pipe devono essere rimosse dal file system alla terminazione dei due processi. ==== Esercizio 4: Un server e molti client ==== Realizzare un processo server che rimane sempre attivo in attesa di richieste da parte di un insieme (possibilmente vuoto) di processi client. Ogni client richiede al server la trasformazione di tutti i caratteri minuscoli di una stringa in caratteri maiuscoli (es ''tigre'' -->''TIGRE'') con un messaggio su una pipe dal nome fissato: //clientserver//. In questo caso i messaggi sulla pipe //clientserver// sono scritti da processi client diversi. Ogni client prima di inviare una richiesta crea una pipe di ascolto dal nome unico (eg. usando il PID) e codifica tale nome nel messaggio inviato al server. All sua attivazione il server crea la pipe clientserver (se non esiste), la apre e si mette in attesa di messaggi da parte dei client. Ogni messaggio è costituito da una stringa e dal nome della pipe di risposta //clientpid//. Per ogni messaggio ricevuto il server estrae la stringa, trasforma le minuscole in maiuscole e invia il risultato su //clientpid//. Il server deve rimanere sempre attivo, anche alla terminazione di tutti i processi client.\\ Tutte le pipe devono essere rimosse dal file system alla terminazione del processo/i che le utilizzano. ==== Esercizio 5: Un server e molti client (multithreaded con socket) ==== Creare un server che utilizzi le socket AF_UNIX e piu' thread concorrenti per gestire un numero di client. Ogni client all'avvio decide quanti messeggi inviare (casualmente fra 1 e N_MSG_MAX). Tutti i messaggi inviati contengono il PID del processo client che li invia. Il srever stampa tutti i messaggi ricevuti sullo standard output. Il server e' realizzato usando piu' thread. Un thread //dispatcher// che accetta le connessioni dai vari client e un thread //worker// per ogni client. Il thread //worker// viene attivato appena la connessione si stabilisce e si occupa di leggere i messaggi del client e stamparli sullo stdout. Quando il client termina l'invio (EOF) il thread //worker// corrispondente termina e libera la memoria occupata. **Elaborazione:** Invece di attivare un thread worker per ogni client attivare un pool di worker all'inizio e schedulare le richieste arrivate sul pool in modo da bilanciare il carico dei vari worker. ==== Esercizio 6: Un server e molti client (single thread) ==== Realizzare un server ed un client analoghi a quelli dell'esercizio 5 senza usare i therad. Utilizzare la //select// per risolvere il non determinismo fra l'accettazione di nuove connessioni e la lettura dei messaggi dai client gia' connessi. ==== Esercizio 7: Big and little endians ==== Scrivere un programma che converte il numero 0x3A4C rappresentato su due byte in //network byte order// e stampa il valore dei due byte da quello di indirizzo minore. Riconvertire il risultato in //host byte order// e stampare ancora i due byte a partire da quello di indirizzo minore. ==== Esercizio 8: Get HTTP ==== Scrivere un programma C che scarica la home page dal server ''173.194.35.31'' inviando una richiesta #define REQUEST "GET / HTTP/1.0\r\n\r\n" sulla porta 80. **Elaborazione:** Utilizzare ''getaddrinfo'' per ottenere l'indirizzo per il server web di google in italia ("www.google.it")