Cognome: Nome: Matricola: Reti di Calcolatori L-A Compito A Parte Java Compito A Sviluppare un applicazione C/S che permetta al client di recuperare dal server: informazioni relative agli orari di un corso (orari_corso); informazioni relative a quali corsi si tengono in un giorno (corsi_giorno). E obbligatorio mettere Cognome Nome Matricola e compito all inizio di ogni file sorgente, pena la non valutazione del compito, che può essere stampato in modo automatico, solo in caso siano presenti gli elementi detti sopra Leggete con attenzione le specifiche del problema prima di impegnarvi a testa bassa nello sviluppo delle singole parti. Naturalmente, i componenti da consegnare devono essere stati provati. Si devono consegnare tutti i file sorgente e tutti gli eseguibili prodotti (per favore, solo quelli relativi ai file sorgente consegnati!!!). La prova intende valutare le capacità progettuali e di programmazione sia in ambiente Java che in ambiente C, pertanto è consigliabile sviluppare, almeno in parte, entrambe le soluzioni richieste. In entrambi gli esercizi, sia Java che C, si effettuino gli opportuni controlli sui parametri della richiesta e si gestiscano le eccezioni, tenendo presente i criteri secondo cui si possa ripristinare il funzionamento del programma oppure si debba forzarne la terminazione. **************************************************************************************************************** La struttura dati, da implementare opportunamente sia in Java che in C, a cui fanno riferimento gli esercizi rappresenta la tabella degli orari di una palestra, e contiene i corsi nella varie giornate della settimana: ORE LUN MAR MER GIO VEN 10 yoga add. & stretch. yoga add. & stretch yoga 11 gag total body ginnastica dolce gag ginnastica dolce 12 13 body sculpt step body sculpt step body sculpt 14 15 ginnastica dolce ginnastica dolce gag 16 spinning spinning spinning 17 add. & stretch. yoga add. & stretch. yoga add. & stretch. 18 total body aerobica total body aerobica total body 19 step total body step total body step 20 spinning funky spinning funky spinning Con più dettaglio, si sviluppino: un client e un server che realizzino il servizio orari_corso usando messaggi datagram: il client chiede ciclicamente da console all utente il nome del corso di cui vuole conoscere gli orari, fino alla fine del file di input da tastiera. Il client invia la richiesta al server e stampa a video l esito dell operazione in base alla risposta ottenuta dal server; il server effettua la selezione dei dati richiesti dalla tabella dei corsi, e invia la risposta (una stringa contenente una sequenza di giorni e orari) al client. un client e un server che realizzino il servizio corsi_giorno usando una connessione: il client chiede ciclicamente da console all utente il giorno di cui vuole conoscere i corsi, fino alla fine del file di input da tastiera. Il client invia la richiesta al server e stampa a video le informazioni ottenute dal server; il server effettua la selezione dei dati richiesti dalla tabella dei corsi, e li invia al client. Parte C Utilizzando RPC sviluppare un applicazione C/S che consenta di effettuare operazioni remote relative ai corsi, realizzate da due diverse rpc: Corsi corsi_orario(int orario) int prenota_spinning(prenotazione p) corsi_orario permette di ottenere i corsi relativi ad un certo orario. Ha come valore di ritorno una struttura dati, Corsi, che raccoglie i nomi dei corsi relativi ad un certo orario (cinque stringhe). prenota_spinning consente di prenotare una lezione di spinning, il cui numero di posti, 20 per ogni lezione, è memorizzato in un vettore di interi decrementati per ogni prenotazione. Ha come parametro una struttura dati, Prenotazione, che contiene giorno e orario della lezione (una stringa e un intero), e restituisce un intero pari al numero di posti ancora disponibili dopo il decremento in caso di esito positivo, e 1 in caso di posti esauriti; Più in dettaglio: il client chiede ciclicamente all utente i dati della richiesta, ovvero i dati della prenotazione oppure l orario di interesse, fino alla fine del file di input da tastiera. Per ogni ciclo, in base al tipo di operazione richiesta dall utente, esegue una chiamata all opportuna procedura remota, passando come parametro un intero nel primo caso, una struttura di tipo Prenotazione nel secondo caso. Il client poi stampa il risultato dell operazione ricavato dal valore di ritorno della procedura. il server esegue la procedura remota che effettua l operazione richiesta, e restituisce al client la struttura dati con i nomi dei corsi nel primo caso, l esito dell operazione (numero di posti oppure 1) nel secondo caso. 1 2
Parte Java Struttura dati public class Corsi Soluzione String nome[][] = new String[10][5]; public Corsi() // qualche campo a caso... for(int i = 0; i < 10; i++) for(int j = 0; j < 5; j++) nome[i][j] = "step"; nome[0][0] = "yoga"; nome[1][0] = "yoga"; nome[2][0] = "yoga"; nome[0][1] = "gag"; nome[1][1] = "gag"; nome[2][1] = "gag"; nome[3][4] = ""; public String cerca(string corso) String giorno = ""; String linea = ""; for(int i = 0; i < 10; i++) for(int j = 0; j < 5; j++) if(nome[i][j].equals(corso)) if(j == 0) giorno = "Lunedi"; if(j == 1) giorno = "Martedi"; if(j == 2) giorno = "Mercoledi"; if(j == 3) giorno = "Giovedi"; if(j == 4) giorno = "Venerdi"; linea+="ore "+(i+10)+" del giorno "+ giorno+"\n"; return linea; Client orari_corso (datagram) import java.io.*; import java.net.*; public class orari_corso public static void main(string[] args) /* Controllo argomenti */ InetAddress addr = null; int port = -1; if(args.length == 2) addr = InetAddress.getByName(args[0]); port = Integer.parseInt(args[1]); else System.out.println("Usage: java orari_corso"+ " serverip serverport"); catch(unknownhostexception e) System.out.println("Problemi..."); System.out.println("LineClient: interrompo..."); System.exit(2); DatagramSocket socket = null; // la creazione e bind alla porta locale socket = new DatagramSocket(); socket.setsotimeout(30000); System.out.println("Orari_corso: avviato"); System.out.println("Creata la socket: " + socket); catch(socketexception e) System.out.println("orari_corso: interrompo..."); 3 4
BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); String richiesta = null; System.out.print("\n^D(Unix)/^Z(Win)+invio... "); // ciclo while di interazione con l utente while (stdin.readline()!= null) System.out.print("Nome corso? "); richiesta = stdin.readline(); catch(exception e) System.out.print("\n^D(Unix)/^Z(Win)+invio..."); DatagramPacket packetout = DatagramUtility.buildPacket(addr, port, richiesta); socket.send(packetout); // invio System.out.println("Richiesta inviata."); catch(ioexception e) System.out.print("\n^D(Unix)/^Z(Win)+invio..."); String risposta = null; risposta = DatagramUtility. getcontent(packetin); System.out.println("Risposta: \n" + risposta); catch(ioexception e) System.out.print("\n^D(Unix)/^Z(Win)..."); System.out.print("\n^D(Unix)/^Z(Win)..."); // while //try catch(exception e) System.out.println("corsi_giorno: termino..."); socket.close(); DatagramPacket packetin = null; byte[] buf = new byte[10000]; packetin = new DatagramPacket(buf, buf.length); socket.receive(packetin); // ricezione catch(ioexception e) System.out.print("\n^D(Unix)/^Z(Win)+invio..."); 5 6
Server datagram import java.io.*; import java.net.*; public class ServerDatagram public static final int PORT = 5000; public static void main(string[] args) Corsi corsi = new Corsi(); int port = -1; /* controllo argomenti */ if(args.length == 1) port = Integer.parseInt(args[0]); else if(args.length == 0) port = PORT; else System.out.println("Usage:..."); //try catch(exception e) System.out.println("Problemi, i seguenti: "); System.out.println("Usage:..."); System.out.println("server: avviato"); DatagramSocket socket = null; // creazione della socket datagram socket = new DatagramSocket(port); System.out.println("Creata la socket: " + socket); catch(socketexception e) 7 // ciclo di servizio while (true) // ricezione del datagramma DatagramPacket packet = null; InetAddress mittaddr = null; int mittport = 0; byte[] buf = new byte[20]; packet = new DatagramPacket(buf, buf.length); socket.receive(packet); // ricezione mittaddr = packet.getaddress(); mittport = packet.getport(); System.out.println("Ricevuta richiesta."); catch(ioexception e)... // lettura della richiesta String linee = ""; String richiesta; richiesta = DatagramUtility.getContent(packet); String p = corsi.cerca(richiesta); System.out.println(p); packet = DatagramUtility. buildpacket(mittaddr, mittport, p); catch(ioexception e) linee = "Problemi nella creazione del"+ " pacchetto. Probabile numero troppo elevato di linee\n"; packet = DatagramUtility. buildpacket(mittaddr, mittport, linee); socket.send(packet); //invio catch(ioexception e)... // while //try catch(exception e) System.out.println("ServerDatagram: termino..."); socket.close(); 8
Client corsi_giorno import java.net.*; import java.io.*; public class corsi_giorno public static void main(string[] args) throws IOException InetAddress addr = null; Socket socket = null; DataInputStream insock = null; DataOutputStream outfile = null; DataOutputStream outsock = null; boolean ok; int port = -1; /* Controllo argomenti */ if(args.length == 2) addr = InetAddress.getByName(args[0]); port = Integer.parseInt(args[1]); else System.out.println("Usage: java corsi_giorno serverip serverport"); catch(unknownhostexception e)... System.exit(2); System.out.println("Corsi_giorno avviato"); // creazione stream di input da tastiera BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); String nomefile = null; int numlinee = 0; System.out.print("\n^D(Unix)/^Z(Win)..."); String giorno; // interazione con l utente while (stdin.readline()!= null) System.out.print("Nome del giorno :"); 9 giorno = stdin.readline(); catch(exception e)... // creazione socket socket = new Socket(addr, port); socket.setsotimeout(10000); catch(exception e)... // creazione stream di input/output su socket outsock = new DataOutputStream( socket.getoutputstream()); insock = new DataInputStream( socket.getinputstream()); catch(ioexception e)... outsock.writeutf(giorno); // invio String ricezione = insock.readutf();//ricezione if(ricezione.equals("ok")) System.out.println("Ricevo: \n"); ricezione = insock.readutf();//ricezione dati System.out.println("Corsi: " + ricezione); System.out.println("\nRicezione terminata "); else if(ricezione.equals("no")) System.out.println("Giorno non esistente"); else System.out.println("Errore inaspettato, "); System.exit(3); socket.close(); //chiusura socket catch(exception e)... System.out.print("\n^D(Unix)/^Z(Win)..."); // while non EOF da console catch(exception e) System.out.println("Client: termino..."); stdin.close(); // corsi_giorno 10
Server stream // Server Stream import java.io.*; import java.net.*; public class ServerStream public static final int PORT = 6000; public static void main(string[] args) throws IOException PrintWriter out = null; int num = -1; Corsi corsi = new Corsi(); //creaz. Strutt. dati ServerSocket serversocket = null; Socket clientsocket = null; DataInputStream insock = null; DataInputStream infile = null; DataOutputStream outsock = null; int port = -1; /* controllo argomenti */ if(args.length == 1) port = Integer.parseInt(args[0]); else if(args.length == 0) port = PORT; else System.out.println("Usage:..."); //try catch(exception e)... // eventuali opzioni sulla socket? serversocket = new ServerSocket(port); catch(exception e) while (true) // ciclo di servizio // bloccante finchè non avviene una connessione clientsocket = serversocket.accept(); // per non bloccare indef. il server seq. clientsocket.setsotimeout(30000); catch(exception e)... // creazione stream di input da socket insock = new DataInputStream( clientsocket.getinputstream()); // creazione stream di output su socket outsock = new DataOutputStream( clientsocket.getoutputstream()); String giorno; giorno = insock.readutf(); //ricezione System.out.print("Nome del giorno "); System.out.println(giorno); catch(ioexception e)... // se la richiesta é corretta proseguo if(!giorno.equals("lun") &&!giorno.equals("mar") &&!giorno.equals("mer") &&!giorno.equals("gio") &&!giorno.equals("ven")) // se la richiesta non è corretta non proseguo System.out.println("giorno non valido"); outsock.writeutf("no"); //invio clientsocket.close(); //chiusura socket // il server continua l'esecuzione if(giorno.equals("lun")) num = 0; if(giorno.equals("mar")) num = 1; if(giorno.equals("mer")) num = 2; if(giorno.equals("gio")) num = 3; if(giorno.equals("ven")) num = 4; 11 12
// Preparazione risultato String linea = ""; for(int i = 0; i < 10; i++) linea += "Ore "+(i+10)+" "+ corsi.nome[i][num] + "\n"; outsock.writeutf("ok"); //invio outsock.writeutf(linea); // invio dati clientsocket.close(); //chiusura socket catch(exception e) System.out.println("Problemi nell'invio"); // while (true) //try catch(exception e) // qui non dovrei mai arrivare // ServerStream Parte C File XDR // palestra.x struct Corsi char lun [15]; char mar [15]; char mer [15]; char gio [15]; char ven [15]; ; struct Prenotazione char giorno[4]; int ora; ; program PALESTRA version FILEVERS int SERVER_START_UP(int i) = 1; Corsi CORSI_ORARIO(int orario) = 2; int PRENOTA_SPINNING(Prenotazione p) = 3; = 1; = 0x20000013; 13 14
Client // palestra_c.c #include <stdio.h> #include <rpc/rpc.h> #include "palestra.h" main (int argc, char *argv[]) char *host; CLIENT *cl; int *ris, *start_ok; Corsi *corsi; Prenotazione pren; char str[5]; int orario, ora, start; char c, ok [5] = ""; // controllo argomenti if (argc!= 2) printf ("usage: %s server_host\n", argv[0]); exit (1); host = argv[1]; // creazione gestore di trasporto cl = clnt_create (host, PALESTRA, FILEVERS, "udp"); if (cl == NULL) clnt_pcreateerror (host); exit (1); /* E' necessario inizializzare le strutture dati su cui andranno ad operare le due rpc, cioè la tabella con gli orari delle lezioni e i contatori che tengono traccia dei posti per le lezioni di spinning. Questo non poteva essere fatto ad ogni invocazione delle rpc perchè i valori di queste strutture devono essere mantenuti tra un'invocazione e l'altra, si è resa quindi necessaria una routine di startup del server da eseguire prima di entrare nel ciclo di interazione con l'utente */ start=1; start_ok=server_start_up_1(&start, cl); if (start_ok==null) printf("problemi nell'inizializzazione \n"); exit(-1); else // start_up ok printf("inserire:\nc) per vedere corsi\tp) per prenotare spinning\t^d per terminare: "); while (gets (ok)) if( strchr (ok, 'C')) // visionare corsi printf("orario (10-20): "); while (scanf("%i",&orario)!= 1) char ch; do ch = getchar(); while (ch!= '\n'); gets(str); if ((orario>9) && (orario<21)) printf("richiesto orario: %d\n",orario); // RISPETTARE LO SPAZIO DI NOMI!!! corsi = corsi_orario_1(&orario,cl); if(corsi==null) printf("errore!\n"); else printf ("I corsi sono:\n"); printf ("LUN: %s\nmar: %s\nmer: %s\ngio: %s\nven: %s\n", corsi->lun, corsi->mar, corsi->mer, corsi->gio, corsi->ven); // if ((orario>9) && (orario<21)) 15 16
else printf("orario sbagliato.\n"); // if C if( strchr( ok, 'P') ) // prenotazione printf("giorno (lun, mer, ven): "); scanf("%s",pren.giorno); if ((strcmp(pren.giorno, "lun")!=0) && (strcmp(pren.giorno, "mer")!=0) && (strcmp(pren.giorno, "ven")!=0)) printf("giorno sbagliato\n"); else // giorno ok printf("ora (16 oppure 20): "); while (scanf("%i",&ora)!= 1) //lettura intero char ch; do ch = getchar(); while (ch!= '\n'); if ((ora!=16) && (ora!=20)) printf("ora sbagliata\n"); else // ora ok pren.ora=ora; gets(str); // RISPETTARE LO SPAZIO DI NOMI!!! ris=prenota_spinning_1(&pren,cl); else if(*ris>=0) printf("prenotazione ok, ci sono ancora %d posti disponibili\n",*ris); else if(*ris=-1) printf("non ci sono piu' posti disponibili\n"); // ora ok // giorno ok // if P printf("inserire:\nc) per vedere corsi\tp) per prenotare spinning\t^d per terminare: "); // while // else start_up ok // free della memoria per il gestore di trasporto clnt_destroy (cl); exit (0); if(ris==null) printf("non riesco ad eseguire la rpc.\n"); 17 18
Server // palestra_s.c #include <stdio.h> #include <rpc/rpc.h> #include "palestra.h" Corsi lezioni [11]; int spinning[2][3]; // RISPETTARE LO SPAZIO DI NOMI!!! int * server_start_up_1_svc(int *p, struct svc_req *rqstp) static int result; int i, j; // inizializzazione strutture dati strcpy(lezioni[0].lun,"yoga"); strcpy(lezioni[0].mar,"add&stretch"); strcpy(lezioni[0].mer,"yoga"); strcpy(lezioni[0].gio,"add&stretch"); strcpy(lezioni[0].ven,"yoga");... strcpy(lezioni[10].lun,"spinning"); strcpy(lezioni[10].mar,"funky"); strcpy(lezioni[10].mer,"spinning"); strcpy(lezioni[10].gio,"funky"); strcpy(lezioni[10].ven,"spinning"); for (i=0; i<2; i++) for (j=0; j<3; j++) spinning[i][j]=20; result=0; return &result; //passaggio per riferimento // server_start_up // RISPETTARE LO SPAZIO DI NOMI!!! int * prenota_spinning_1_svc(prenotazione *pren, struct svc_req *rqstp) static int result; int g, o; result=-1; if (strcmp(pren->giorno, "lun")==0) g=0; else if (strcmp(pren->giorno, "mer")==0) g=1; else if (strcmp(pren->giorno, "ven")==0) g=2; else g=-1; if (pren->ora==16) o=0; else if (pren->ora==20) o=1; else o=-1; // attenzione alle condizioni logiche!! if ((g!=-1 && o!=-1) && (spinning[o][g]>0)) spinning[o][g]-=1; result=spinning[o][g]; return &result; //passaggio per riferimento else return &result; // prenota_spinning // RISPETTARE LO SPAZIO DI NOMI!!! Corsi * corsi_orario_1_svc(int *orario, struct svc_req *rqstp) static Corsi result; result = lezioni[*orario-10]; return &result; //passaggio per riferimento // corsi_orario 19 20