codice:import java.io.*; import java.net.*; class Serv { final static int SECS = 1; final static int PORT = 12345; public static void main (String args[]) { ServerSocket welcomeSocket = (ServerSocket)null; Socket serviceSocket = (Socket)null; try { welcomeSocket = new ServerSocket(Serv.PORT); while (true) { serviceSocket = welcomeSocket.accept();//assegna una service socket ad ogni richiesta di connessione Fork serviceThread = new Fork(serviceSocket); serviceThread.start(); } } catch(Exception e) { e.printStackTrace(); } } } class Fork extends Thread { //questo thread genera un server multithreading private Socket sock; public Fork(Socket sock) { // this.sock = sock; } public void run() { try{ //probabilmente logs riguarda il loging dei comandi Logs l = new Logs(this.sock); InputStream i = this.sock.getInputStream(); //canale di input per le richieste dal client OutputStream o = this.sock.getOutputStream(); //can output Data d = new Data(i, l); // a questo thrad passiamo il canale di input, serve per mandare mess al client Comp c = new Comp(o, l); // a questo thread passiamo il can di output, gestisce la com di ritorno dal client //sia data che comp hanno in ingresso l,logs, perciò lasceranno traccia del loro operato in qualche modo d.comp = c; // è la maniera per far conoscere al thread d chi è il thread c c.data = d; //viceversa; i due thread dovranno probabilmente cooperare tra loro, qusta è la loro presentazione //crea la musica è li invia al client d.start(); c.start(); } catch (Exception e) { e.printStackTrace(); } } } class Comp extends Thread {//immette nel canale di output delle note ottenute da un calcolo casuale basato sul i valori OutputStream chan; //di data, il canale di inputstream. Logs logs; Data data; public Comp(OutputStream chan, Logs logs) { this.chan = chan; this.logs = logs; } public void run() { this.logs.log("Comp started"); try { while (true) { while (this.data.isOn()) { // quando isOn + true int alt[] = this.data.getAlt();//getalt e getdut restituiscono un array di valori, per le alt e dur: il min e il max valore int dur[] = this.data.getDur(); Note note = new Note(alt[0], alt[1], dur[0], dur[1]); note.xmit(this.chan); //stampa i valori delle note ottenute da random tra val min e max.In ingresso ha una variabile di output this.logs.log("Note " + Note.qty + " = ("+ note.alt + "," + note.dur + ")"); } yield();// da CERCARE SUL MANUALE appartiene alla classe thread visto che siamo nella classe therad e non è estensione di nient'altro } //yield---> fa uscire il therad corrente dalla cpu(se un processo ne ha più bisogno lui cede il posto) } catch (Exception e) { this.logs.log("Exiting - Connection reset"); this.stop(); } } } class Note { static int qty = 0; int alt; int dur; public Note(int minalt, int maxalt, int mindur, int maxdur) { Note.qty++; // dopo incrementa la quantità, è una variabile static, perchè viene invocata da nota.blabla alt = minalt + (int)(Math.random()*(maxalt - minalt)); dur = mindur + (int)(Math.random()*(maxdur - mindur)); } public void xmit(OutputStream o) throws Exception { o.write((int)this.alt); o.write((int)this.dur); Thread.sleep(10*this.dur); } } class Data extends Thread { InputStream chan; Logs logs; Comp comp; int MINALT = 36;// il range delle altezze è di 4 ottave int MAXALT = 84; int MINDUR = 25; int MAXDUR = 75; boolean ON = false; //sembra essere un interruttore, inizialmente è spento private int minalt;//possono essere variabili temporanee cn cui modificare il valore degli omonimi private int maxalt; private int mindur; private int maxdur; public Data(InputStream chan, Logs logs) { this.chan = chan; this.logs = logs; } public void run() { this.logs.log("Data started"); try { int b; // il primo byte è un comando, il 2° pure, while ((b=this.chan.read()) != -1) {//fintantochè la read non legge -1, ovvero finchè è diverso da -1, che è l'end of file(del canale di input). this.logs.log("Command = " + b); switch (b) {// b è il valore che leggiamo dalla read case 0: setOff(); //se leggiamo ,dalla read, 0, facciamo un set off, spegnamo il dispositivo this.logs.log("Stopped @ note: " + Note.qty); break; case 1: setOn();//se leggiamo ,dalla read, 1, facciamo un set on, accendiamo il dispositivo this.logs.log("Resumed @ note: " + Note.qty); break; case 2: minalt = this.chan.read();//vengono innizializzate con i valori ricevuti, ma sono lo stesso valore per max e min? maxalt = this.chan.read(); if (minalt <= maxalt) setAlt();//questa if serve per controllare che il client non invii un valore minimo + grande del corrispettivo val massimo this.logs.log("Pitch = [" + MINALT + "," + MAXALT + "]"); break; case 3: mindur = this.chan.read(); maxdur = this.chan.read(); if (mindur <= maxdur) setDur(); this.logs.log("Rythm = [" + MINDUR + "," + MAXDUR + "]"); break; } } } catch (Exception e) { this.logs.log("Exiting - Connection reset"); setOn(); this.stop(); } } synchronized void setOn() { ON = true; // set on manda in true l'interruttore notify(); } synchronized void setOff() { //set of lo manda in false ON = false; notify(); } synchronized boolean isOn() { while (!ON) try {wait();} catch (Exception e) {}; // quando on è falso lo manda in wait //quando l'interruttore è acceso, aspetta return ON; } synchronized void setAlt() { MINALT = minalt; // le variabili temporanee travasano il loro valore nei campi dell'oggetto di classe MAXALT = maxalt; } synchronized int[] getAlt() { //scrive in un array lungo 2 elem,da0 a 1, i valori MINAL E MAXALT, definiti nella classe data int alt[] = new int[2]; alt[0] = MINALT; // minalt è il primo elemento dell'array alt[1] = MAXALT; //tra i return alt; } synchronized void setDur() { MINDUR = mindur; MAXDUR = maxdur; } synchronized int[] getDur() { int dur[] = new int[2]; dur[0] = MINDUR; dur[1] = MAXDUR; return dur; } } // La classe che segue serve solo per creare e gestire il file di log. // L'unico metodo di cui e' utile conoscere il funzionamento e' "log". class Logs { final static String PATH = "/home/gfp/Logs/ProMus/Logs-20-07-07/Tur1/"; final static String LOGS = "logs"; private Socket sock; // è la socket che parla con il client DataOutputStream logs; public Logs(Socket sock) { this.sock = sock; InetAddress addr = this.sock.getInetAddress(); //prendiamo l'indirizzo del client int port = this.sock.getPort(); String name = addr.getHostName(); String ipv4 = addr.getHostAddress();//prendiamo l'ip del client new File(Logs.PATH + ipv4).mkdir(); //creiamo una nuova directory con il nome passato come parametro di File(nome) try { this.logs = //java ha implementate 40classi che riguardano file, per i vari scopi cui possono servire. new DataOutputStream( new FileOutputStream( // poi lo trasforiamo in un file di outputstream new File(Logs.PATH + ipv4 , Logs.LOGS), true)); } catch (FileNotFoundException e) { System.out.println("No log file created: " + name + "[" + ipv4 + "]"); e.printStackTrace(); return; } log("****************************"); log("Client Name = " + name); log("Client Addr = " + ipv4); log("Client Port = " + port); } synchronized void log(String mess) { String name = Thread.currentThread().getName(); //prende il nome del thread corrente e scrive un messaggio nel file di log try { this.logs.writeBytes(name + " - " + mess + "\n"); //la trasformazione di questi file in tipo outputstrem è dovuta forse, dal fatto che per comodità usiamo il metodo writebyte } catch (IOException e) { e.printStackTrace(); } } }