Programmare con le Socket TCP in java 2: Application Layer 1 Il Client contatta il server Il Server: Il processo server è sempre attivo in attesa di connessioni (demone) Crea una socket per accettare la connessione del client (“socket di benvenuto”, java.net.ServerSocket) Il Client: Crea una socket TCP locale, specificando l’indirizzo IP e numero di porta del processo server Quando il client crea la socket: il lato client TCP stabilisce una connessione con il server TCP (connessione implicita nel costruttore di java.net.Socket) 2: Application Layer 2 Il server riceve una connessione Quando viene contattato dal client, il TCP nel server crea una nuova socket per far comunicare il processo server con il nuovo client Un server può interagire con molti client contemporaneamente Il TCP usa il numero di porta sorgente per distinguere i pacchetti di diverse connessioni attive (insieme all’indirizzo IP) Dal punto di vista dell’applicazione TCP fornisce un trasferimento di byte (un “tubo”) affidabile e ordinato tra le socket aperte dai processi client e server Dopo che è stata stabilita la connessione, le socket usate dal client e dal server sono equivalenti: Possono inviare e ricevere dati Un protocollo applicativo governa l’ordine in cui parlano 2: Application Layer 3 Gli Stream - gergo Uno stream (flusso) è una sequenza di caratteri che fluisce verso un processo o da un processo Un input stream è collegato a qualche sorgente di input del processo, come la tastiera, un file o una socket. Un output stream è collegato a qualche destinazione di output, come il monitor, un file o una socket. 2: Application Layer 4 Socket in java Package java.net Classe java.net.Socket un canale di comunicazione verso un processo remoto Costruttore Socket(InetAddress address, int port) costruisce una Socket e crea una connessione al server address,port (usata dal client) Classe java.net.ServerSocket un punto di accesso ad un server per nuove connessioni Costruttore ServerSocket(int port) crea una ServerSocket in attesa su una determinata porta TCP Metodo Socket java.net.ServerSocket.accept() si mette in attesa di connessioni, quando ne riceve una restituisce la relativa Socket (usata dal server). È un metodo bloccante. 2: Application Layer 5 Socket e stream Una volta stabilita la connessione, client e server usano entrambi un oggetto di tipo Socket Metodo InputStream java.net.Socket.getInputStream() restituisce il flusso per leggere i dati provenienti dalla Socket Metodo OutputStream java.net.Socket.getOutputStream() restituisce il flusso per inviare i dati verso la Socket Metodo java.net.Socket.Close() chiude la connessione TCP 2: Application Layer 6 Gli Stream delle socket TCP Quando due processi hanno stabilito una connessione TCP usando le socket, l’input stream della socket nel processo A è collegato all’output stream della socket corrispondente nel processo B, e viceversa si realizza un canale di comunicazione interprocesso remoto Processo A input Processo B TCP socket TCP socket stream Socket outToB stream IP network Socket inFromB output outToA inFromA output input stream stream 2: Application Layer 7 Programmazione con le socket TCP Processo Client input stream output stream inFromServe inFromUse 1) Il client legge una riga dallo reads standard input (stream inFromUser), e la manda al server usando la socket (stream outToServer ) 2) Il server legge la riga dalla socket 3) Il server converte la riga in caratteri maiuscoli, e la rimanda indietro al client 4) Il client legge dalla socket (stream inFromServer ) la riga modificata, e la stampa terminale outToServe Esempio di applicazione client-server: tastiera clientSocke client TCP socket to network input stream TCP socket from network 2: Application Layer 8 Interazione Client/server con le socket : TCP Server (in esecuzione su hostid) Client Crea una socket, port=x, per le richieste in arrivo, e aspetta welcomeSocket = ServerSocket(x) TCP Attende richieste di connection setup connessione in ingresso connectionSocket = welcomeSocket.accept() Legge la richiesta da connectionSocket Scrive la risposta su connectionSocket chiude connectionSocket Crea una socket, Connessa a hostid, port=x clientSocket = Socket(hostid, port) Invia la richiesta usando clientSocket Legge la risposta da clientSocket chiude clientSocket 2: Application Layer 9 Esempio: Java client (TCP) import java.io.*; import java.net.*; class TCPClient { public static void main(String argv[]) throws Exception { String sentence; String modifiedSentence; Crea un input stream Crea la socket client, Connessa al server Crea un output stream Connesso alla socket BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in)); Socket clientSocket = new Socket("hostname", 6789); DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream()); 2: Application Layer 10 Esempio: Java client (TCP), cont. Crea un input stream Connesso alla socket BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); sentence = inFromUser.readLine(); Manda una riga al server outToServer.writeBytes(sentence + '\n'); Legge una riga dal server modifiedSentence = inFromServer.readLine(); System.out.println("FROM SERVER: " + modifiedSentence); clientSocket.close(); } } 2: Application Layer 11 Esempio: Java server (TCP) import java.io.*; import java.net.*; class TCPServer { Crea una socket di benvenuto Sulla porta 6789 Aspetta sulla socket di benvenuto il contatto del client Crea un input stream, connesso alla socket public static void main(String argv[]) throws Exception { String clientSentence; String capitalizedSentence; ServerSocket welcomeSocket = new ServerSocket(6789); while(true) { Socket connectionSocket = welcomeSocket.accept(); BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream())); 2: Application Layer 12 Esempio: Java server (TCP), cont Crea un output stream, connesso alla socket DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream()); Legge una riga dalla socket clientSentence = inFromClient.readLine(); capitalizedSentence = clientSentence.toUpperCase() + '\n'; Scrive una riga sulla socket outToClient.writeBytes(capitalizedSentence); } } } Fine del loop while Torna all’inizio in attesa di una nuova connessione 2: Application Layer 13 gestione delle eccezioni TCP Se non è possibile effettuare una connessione TCP, il TCP informa l’applicazione che la ha richiesta generando una eccezione, che interrompe il flusso dell’esecuzione se non viene catturata Una eccezione è un oggetto appartenente ad una sottoclasse di java.lang.Exception Le istruzioni nel blocco try possono generare eccezioni, che vengono gestite nel blocco catch appropriato per il tipo dell’eccezione Una connessione fallita viene segnalata con una java.net.ConnectException try { clientSocket = new Socket(argv[0], 6789); } catch (java.net.ConnectException e){ System.out.println("connection failed:\n" + e); } 2: Application Layer 14 Programmazione con le socket UDP UDP: non c’è connessione tra client e server Non è necessario stabilire la connessione Il mittente inserisce esplicitamente l’indirizzo IP e la porta della destinazione in ogni pacchetto Il server deve estrarre l’indirizzo IP e la porta del mittente dal pacchetto ricevuto Punto di vista dell’applicazione: UDP fornisce un trasferimento non affidabile di gruppi di byte (“datagrammi”) tra client e server UDP: i dati ricevuti possono essere persi o ricevuti fuori ordine 2: Application Layer 15 Interazione Client/server con le socket: UDP Server (in esecuzione su hostid) Crea una socket, port=x, per le richieste in arrivo: serverSocket = DatagramSocket(x) Legge le richieste da serverSocket Scrive le risposte su serverSocket Specificando indirizzo IP e porta del client Client Crea una socket, clientSocket = DatagramSocket() Crea, indirizza (hostid, port=x) Invia il datagramma di richiesta usando clientSocket Legge la risposta da clientSocket chiude clientSocket 2: Application Layer 16 Esempio: Java client (UDP) input stream Client process monitor inFromUser keyboard Process Input: riceve un pacchetto (TCP riceveva un “flusso di byte”) UDP packet receivePacket pacchetto (TCP mandava un “flusso di byte”) sendPacket Output: invia un client UDP clientSocket socket to network UDP packet UDP socket from network 2: Application Layer 17 Esempio: Java client (UDP) import java.io.*; import java.net.*; Crea un input stream Crea la client socket Traduce hostname in un indirizzo IP usando il DNS class UDPClient { public static void main(String args[]) throws Exception { BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in)); DatagramSocket clientSocket = new DatagramSocket(); InetAddress IPAddress = InetAddress.getByName("hostname"); byte[] sendData = new byte[1024]; byte[] receiveData = new byte[1024]; String sentence = inFromUser.readLine(); sendData = sentence.getBytes(); 2: Application Layer 18 Esempio : Java client (UDP), cont. Crea un datagramma con i dati, lunghezza, indirizzo IP, porta Invia il datagramma to server Legge il datagramma dal server DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 9876); clientSocket.send(sendPacket); DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); clientSocket.receive(receivePacket); String modifiedSentence = new String(receivePacket.getData()); System.out.println("FROM SERVER:" + modifiedSentence); clientSocket.close(); } } 2: Application Layer 19 Esempio : Java server (UDP) import java.io.*; import java.net.*; Crea una socket datagramma Sulla porta 9876 class UDPServer { public static void main(String args[]) throws Exception { DatagramSocket serverSocket = new DatagramSocket(9876); byte[] receiveData = new byte[1024]; byte[] sendData = new byte[1024]; Crea spazio per il datagramma ricevuto Rieceve il datagramma while(true) { DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); serverSocket.receive(receivePacket); 2: Application Layer 20 Esempio : Java server (UDP), cont String sentence = new String(receivePacket.getData()); Determina indirizzo IP e porta del mittente InetAddress IPAddress = receivePacket.getAddress(); int port = receivePacket.getPort(); String capitalizedSentence = sentence.toUpperCase(); Crea un datagramma da mandare al client sendData = capitalizedSentence.getBytes(); DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port); Scrive il datagramma Sulla socket serverSocket.send(sendPacket); } } } Fine del loop while torna all’inizio e attendi un altro datagramma 2: Application Layer 21