Università degli Studi della Calabria Corso di Laurea in Ingegneria Informatica A.A. 2010/2011 Corso di Reti di Calcolatori Lucidi delle Esercitazioni Raffaele Giordanelli 1 Si vuole implementare un server che gestisce scommesse sulle corse dei cavalli. Il server riceve le scommesse da parte di utenti client che indicano il numero del cavallo (da 1 a 12) su cui vogliono puntare. Le scommesse sono ricevute, tramite il protocollo TCP, sulla porta 8001 del server. Il client effettua una scommessa inviando al server la stringa “<num_cavallo> <puntata>”, in cui <num_cavallo> è il numero del cavallo, e <puntata> è l’ammontare in euro della scommessa. Il server accetta le scommesse fino all’ora <ora_limite>. A tal fine un thread del server controlla periodicamente, es. ogni minuto, l’ora del sistema. Quando l’ora corrente raggiunge l’ora <ora_limite>, il server deve chiudere l’accettazione delle scommesse. Il server memorizza in un’opportuna struttura dati le scommesse pervenute. Scaduto il tempo utile, il server verifica il numero del cavallo vincente (a tal proposito si può utilizzare un metodo che estrae un numero casuale da 1 a 12), e successivamente comunica a tutti gli scommettitori i vincitori e le somme da essi vinte. Tale comunicazione avviene tramite l’invio, sulla porta UDP 8002 di ogni client, della stringa “Somma vinta = <somma>” per ogni scommessa vincente. <somma> è l’ammontare della eventuale somma vinta, corrispondente 2 alla scommessa effettuata dal client moltiplicata per 12. import java.io.*; import java.net.*; import java.util.*; class BetClient{ int serverPort; int myPort; InetAddress groupAddress; InetAddress serverAddress; Socket s; public BetClient(InetAddress gAddress, InetAddress server, int sPort, int mP groupAddress=gAddress; serverAddress=server; serverPort=sPort; myPort=mPort; try{ s=new Socket(serverAddress, serverPort); } catch (IOException ioe){ System.out.println(ioe); } } 3 public boolean placeBet(int nCavallo, long puntata){ String e=""; try{ BufferedReader in = new BufferedReader (new InputStreamReader (s.getInputStream())); PrintWriter out = new PrintWriter (s.getOutputStream(),true); String bet =nCavallo+" "+puntata; out.println(bet); e=in.readLine(); } catch (IOException ioe){ System.out.println(ioe);} return e.equals("Scommessa accettata."); } 4 public void riceviElenco(){ try{ MulticastSocket socket=new MulticastSocket(myPort); socket.joinGroup(groupAddress); byte[] buf=new byte[256]; DatagramPacket packet=new DatagramPacket(buf,buf.length); socket.receive(packet); String elenco= new String(packet.getData()); System.out.println("Elenco vincitori: "); System.out.println(elenco); } catch (IOException ioe){ System.out.println(ioe); } } 5 public static void main (String[] args){ int serverPort=8001; int myPort=8002; try{ InetAddress group=InetAddress.getByName("230.0.0.1"); InetAddress server=InetAddress.getByName("127.0.0.1"); BetClient client=new BetClient(group,server,serverPort,myPort); int nCavallo=((int)(Math.random()*12))+1; if (client.placeBet(nCavallo, 15)) client.riceviElenco(); }catch (UnknownHostException uhe){ System.out.println(uhe);} }// main }// BetClient 6 import java.io.*; import java.net.*; import java.util.*; class BetServer{ private private private private private HashMap scommesse; Calendar limite; BetAccepter accepter; BetDenyer denyer; int port; public BetServer(int port, Calendar deadline){ scommesse=new HashMap(); limite=deadline; this.port=port; accepter=new BetAccepter(port); accepter.start(); } 7 class BetAccepter extends Thread{ private int port; private ServerSocket serv; private boolean accept; BetAccepter (int p){ try{ port=p; serv=new ServerSocket(port); accept=true; } catch (IOException ioe){ System.out.println(ioe); } } public void run(){ while(accept){ try{ Calendar now=Calendar.getInstance(); serv.setSoTimeout((int)(limite.getTimeInMillis()now.getTimeInMillis())); Socket k=serv.accept(); 8 BufferedReader in = new BufferedReader (new InputStreamReader (k.getInputStream())); PrintWriter out = new PrintWriter (k.getOutputStream(), true ); String line=in.readLine(); int pos=line.indexOf(" "); int numCavallo=Integer.parseInt(line.substring(0,pos)); long puntata=Long.parseLong(line.substring(pos+1)); InetAddress ip=k.getInetAddress(); Scommessa s=new Scommessa(numCavallo,puntata,ip); int key=s.getID(); scommesse.put(new Integer(key),s); //manda ok out.println("Scommessa accettata."); out.close(); k.close(); System.out.println("Ricevuta scommessa "+ip+" "+numCavallo+" "+puntata); 9 } catch (SocketTimeoutException ste){ accept=false; System.out.println("Tempo a disposizione per le scommesse terminato"); }// catch catch (IOException ioe){ System.out.println(ioe);} }//while try{ serv.close(); } catch (IOException ioe){ System.out.println(ioe);} }// run }// BetAccepter 10 class BetDenyer extends Thread{ private int port; private ServerSocket serv; private boolean closed; BetDenyer (int p){ try{ port=p; serv=new ServerSocket(port); closed=true; } catch (IOException ioe){ System.out.println(ioe);} } public void reset(){ closed=false; } 11 public void run(){ try{ while(closed){ Socket k=serv.accept(); PrintWriter out = new PrintWriter(k.getOutputStream(),true); out.println("Scommesse chiuse"); out.close(); k.close(); System.out.println("Rifiutata scommessa"); }//while serv.close(); } catch (IOException ioe){ System.out.println(ioe);} }// run }// BetDenyer 12 public void attendiChiusuraScommesse(){ try{ accepter.join(); } catch (InterruptedException ie){ System.out.println(ie);} } public void chiusuraScommesse(){ denyer=new BetDenyer(port); denyer.start(); } public void resetServer(){ denyer.reset(); } public LinkedList controllaScommesse (int cavalloVincente){ LinkedList elenco=new LinkedList(); for (int i=0;i<=scommesse.size();i++){ Scommessa s=(Scommessa)scommesse.get(new Integer(i)); if (s.equals(new Scommessa(cavalloVincente,0,null))) elenco.addLast(s); } return elenco; } 13 public void comunicaVincitori(LinkedList vincitori, InetAddress ind, int port){ ListIterator it=vincitori.listIterator(); try{ MulticastSocket socket=new MulticastSocket(); byte[] buf=new byte[256]; String m=""; while(it.hasNext()){ Scommessa s=(Scommessa)it.next(); m+=s.getCavallo()+" "+(s.getPuntata()*12)+"\n"; } buf=m.getBytes(); DatagramPacket pk=new DatagramPacket(buf,buf.length,ind,port); socket.send(pk); } catch (IOException ioe){ System.out.println(ioe);} } 14 public static void main (String[] args){ int serverPort=8001; int clientPort=8002; try{ InetAddress multiAddress=InetAddress.getByName("230.0.0.1"); LinkedList elenco; Calendar deadline=Calendar.getInstance(); deadline.add(Calendar.MINUTE,1); BetServer server=new BetServer(serverPort, deadline); server.attendiChiusuraScommesse(); server.chiusuraScommesse(); int vincente=((int)(Math.random()*12))+1; System.out.println("E' risultato vincitore il cavallo "+vincente); elenco=server.controllaScommesse(vincente); server.comunicaVincitori(elenco,multiAddress,clientPort); System.out.println("Elenco vincitori:"); System.out.println(elenco); Thread.sleep(150000); server.resetServer(); } catch (InterruptedException ie){ System.out.println(ie); } catch (UnknownHostException uhe){ System.out.println(uhe); } }// main }// BetServer 15 import java.net.InetAddress; public class Scommessa { private int ID_scommessa; private int N_cavallo; private long puntata; private InetAddress scommettitore; private static int nextID=1; public Scommessa (int n_cavallo, long punt, InetAddress scommett){ ID_scommessa=nextID++; N_cavallo=n_cavallo; puntata=punt; scommettitore=scommett; } 16 public boolean equals(Object o){ if (!(o instanceof Scommessa)) return false; Scommessa s=(Scommessa)o; return N_cavallo==s.N_cavallo; } public int getCavallo(){ return N_cavallo; } public int getID(){ return ID_scommessa; } public long getPuntata(){ return puntata; } public InetAddress getScommettitore(){ return scommettitore; } } 17 Si realizzi una applicazione Communicator che, installata sulle macchine di una rete locale, consenta agli utenti delle diverse macchine di comunicare tra loro. Il Communicator dovrà offrire due funzionalità: Consentire la scoperta degli altri Communicator attivi sulla rete. La scoperta è effettuata inviando un messaggio in broadcast sulla rete e ricevendo le risposte dei Communicator attivi. Consentire la comunicazione con un determinato Communicator; la comunicazione consiste nello scambio di messaggi (stringhe) mediante il protocollo TCP. Ogni Communicator dovrà quindi implementare un modulo Client ed un modulo Server che operano in parallelo: Il modulo Client consente all’utente di effettuare richieste per scoprire i Communicator attivi e per inviare messaggi ad altri Communicator. Il modulo Server gestisce la ricezione dei messaggi broadcast e l’invio delle relative risposte, nonché la ricezione dei messaggi TCP e la visualizzazione del loro contenuto. 18 Un messaggio broadcast di scoperta contiene l’indirizzo IP del Communicator mittente e la porta TCP usata dal modulo Server dello stesso mittente. I Communicator riceventi rispondono inviando un messaggio TCP a quell’indirizzo ed a quella porta. Il messaggio di risposta contiene a sua volta l’indirizzo IP e la porta TCP del Communicator che risponde. Per le comunicazioni in broadcast si utilizzi l’indirizzo 230.0.0.1 e la porta 2000, mentre per le comunicazione TCP ogni Communicator utilizzi una porta scelta dall’utente. import java.io.*; import java.net.*; import java.util.*; class multicastListener extends Thread { int mcastPort; InetAddress remAddress; int tcpPort; multicastListener(int port1, int port2) { this.mcastPort = port1; this.tcpPort = port2; System.out.println("ML>Porta multicast locale = "+mcastPort); System.out.println("ML>Porta tcp locale = "+tcpPort); } 20 public void run () { try { MulticastSocket mSocket = new MulticastSocket(mcastPort); InetAddress group = InetAddress.getByName("230.0.0.1"); mSocket.joinGroup(group); while (true) { // Ricevo datagramma multicast byte[] buf = new byte[50]; DatagramPacket packet = new DatagramPacket(buf, buf.length); mSocket.receive(packet); remAddress = packet.getAddress(); String received = new String (packet.getData()); int i=0; while(Character.isDigit(received.charAt(i)))i++; int remTCPPort = Integer.parseInt(received.substring(0,i)); System.out.println("\nML>Ricevuto mcast datagram da "+ remAddress.getHostAddress()+":"+packet.getPort()); System.out.println("ML>Contenuto del datagram: "+remTCPPort); 21 // Invio messaggio via TCP solo se il datagramma multicast // era stato inviato da un altro Communicator (non da sè stesso) if ( !(remAddress.equals(InetAddress.getLocalHost())) || (remTCPPort! =tcpPort)){ System.out.println("ML>Invio risposta a "+ remAddress.getHostAddress()+":"+remTCPPort); Socket tcpSocket = new Socket(remAddress.getHostAddress() ,remTCPPort); PrintWriter out = new PrintWriter(tcpSocket.getOutputStream(), true); out.println(tcpPort); } } } catch (Exception ex) { System.out.println("ML>"+ex);} } } 22 import java.io.*; import java.net.*; import java.util.*; class socketListener extends Thread { int tcpPort; InetAddress remAddress; int remTCPPort; socketListener(int port) { this.tcpPort = port; System.out.println("SL>Porta tcp locale = "+port); } 23 public void run () { try { ServerSocket sListener = new ServerSocket(tcpPort); while (true) { //Ricevo messaggio risposta via TCP Socket sock = sListener.accept(); InetAddress remAddress = sock.getInetAddress(); BufferedReader in = new BufferedReader (new InputStreamReader(sock.getInputStream())); String line = in.readLine(); int remTCPPort = Integer.parseInt(line); System.out.println("\nSL>Ricevuta risposta da "+ remAddress.getHostAddress()+":"+sock.getPort()); System.out.println("SL>Stringa socket ricevuta: "+remTCPPort); sock.close(); } } catch (Exception ex) { System.out.println("SL>"+ex);} } } 24 import java.io.*; import java.net.*; import java.util.*; class Communicator { static int multicastPort; static int socketPort; static void sendMcastDatagram(){ try { while(true){ byte[] buf = new byte[50]; String strBuf = ""; strBuf += socketPort; buf = strBuf.getBytes(); InetAddress mcastAddress = InetAddress.getByName("230.0.0.1"); MulticastSocket mSocket = new MulticastSocket(); DatagramPacket dp = new DatagramPacket( buf, buf.length, mcastAddress, 2000); System.out.println("\nCO>Invio datagramma multicast"); mSocket.send(dp); Thread.sleep(20000); } }catch (Exception ex){ System.out.println("CO>"+ex);} 25 public static void main(String args[]) { // Sulla porta 2000 ricevo i datagrammi multicast // La porta per le connessioni socket è scelta dall'utente try { multicastPort = 2000; socketPort = Console.readInt("porta TCP>"); multicastListener ml = new multicastListener (multicastPort,socketPort); socketListener sl = new socketListener(socketPort); ml.start(); sl.start(); sendMcastDatagram(); } catch (Exception ex) { System.out.println("CO>"+ex);} } } 26