Aplicaciones Cliente-Servidor Con Sockets puerto Cliente puerto Escucha Cliente puerto Funcionamiento de aplicaciones Cliente-Servidor Cliente Petición de conexión 125.180.34.10 Puerto Puerto Puerto 3012 3000 3011 Servidor Petición de conexión Cecilia M. Curlango Rosas 2/15 Lectura y escritura con sockets 1. Abrir el socket. 2. Abrir un flujo de entrada y uno de salida al socket. 3. Leer y escribir el flujo siguiendo el protocolo del servidor. 4. Cerrar los flujos. 5. Cerrar el socket. Cecilia M. Curlango Rosas 3/15 Antecedente de la Aplicación: Knock Knock Jokes ● Server: "Knock knock!" ● Client: "Who's there?" ● Server: "Dexter." ● Client: "Dexter who?" ● Server: "Dexter halls with boughs of holly." ● Client: "Groan." Cecilia Curlango Rosas 4/15 public class KnockKnockServer { public static void main(String[] args) throws IOException { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(4444); } catch (IOException e) { System.err.println("Could not listen on port: 4444."); System.exit(1); } Socket clientSocket = null; try { clientSocket = serverSocket.accept(); } catch (IOException e) { System.err.println("Accept failed."); System.exit(1); } PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); BufferedReader in = new BufferedReader( new InputStreamReader( clientSocket.getInputStream())); String inputLine, outputLine; KnockKnockProtocol kkp = new KnockKnockProtocol(); outputLine = kkp.processInput(null); out.println(outputLine); while ((inputLine = in.readLine()) != null) { outputLine = kkp.processInput(inputLine); out.println(outputLine); if (outputLine.equals("Bye.")) break; } out.close(); in.close(); clientSocket.close(); serverSocket.close(); } } Cecilia Curlango Rosas 5/15 Crear el Socket y atarlo al puerto try { tryserverSocket { = new ServerSocket(4444); serverSocket = new } catch (IOException e) {ServerSocket(4444); } catch (IOException e) { System.out.println("Could not listen on port: 4444"); System.out.println("Could not listen on port: 4444"); System.exit(-1); System.exit(-1); } } ServerSocket public ServerSocket(int port) throws IOException Creates a server socket, bound to the specified port. A port number of 0 means that the port number is automatically allocated, typically from an ephemeral port range. This port number can then be retrieved by calling getLocalPort. Cecilia Curlango Rosas 6/15 Aceptar conexiones del cliente Socket clientSocket = null; Socket clientSocket = null; try { tryclientSocket { = serverSocket.accept(); clientSocket = serverSocket.accept(); } catch (IOException e) { } catch (IOException e) { System.out.println("Accept failed: 4444"); System.out.println("Accept failed: 4444"); System.exit(-1); System.exit(-1); } } ● ● ● Este método espera a que inicie un cliente y solicite una conexión al host (taranis) y puerto (4444) de este servidor. Cuando se establece una conexión exitosamente, el método regresa un nuevo Socket atado al mismo puerto local y conectado a la dirección y puerto del cliente. Este nuevo Socket lo utilizará el servidor para comunicarse con el cliente al mismo tiempo que recibe peticiones de conexión de otros clientes en el ServerSocket original. Cecilia Curlango Rosas 7/15 Comunicación con el cliente PrintWriter out = new PrintWriter( PrintWriter out = newclientSocket.getOutputStream(), PrintWriter( true); clientSocket.getOutputStream(), true); BufferedReader in = new BufferedReader( BufferedReader in = newnew BufferedReader( InputStreamReader( newclientSocket.getInputStream())); InputStreamReader( String inputLine, outputLine; clientSocket.getInputStream())); String inputLine, outputLine; // initiate conversation with client // initiate conversation with client KnockKnockProtocol kkp = new KnockKnockProtocol(); KnockKnockProtocol kkp = new KnockKnockProtocol(); outputLine = kkp.processInput(null); outputLine = kkp.processInput(null); out.println(outputLine); out.println(outputLine); while ((inputLine = in.readLine()) != null) { while ((inputLine = in.readLine()) != null) { outputLine = kkp.processInput(inputLine); outputLine = kkp.processInput(inputLine); out.println(outputLine); ifout.println(outputLine); (outputLine.equals("Bye.")) if break; (outputLine.equals("Bye.")) break; } } 1. Obtener los flujos de entrada al socket y crear objetos para leer y escribir en ellos. 2. Iniciar la comunicación con el cliente (escribir en el socket). 3. Leer y escribir en el socket para comunicarse con el cliente. Cecilia Curlango Rosas 8/15 Terminar la Comunicación out.close(); out.close(); in.close(); in.close(); clientSocket.close(); clientSocket.close(); serverSocket.close(); serverSocket.close(); ● ● Cerrar los flujos de entrada y salida. Cerrar los sockets del cliente y del servidor. Cecilia Curlango Rosas 9/15 Protocolo Knock Knock Waiting 0 SentKnockKnock SentClue Another 1 2 3 Cecilia Curlango Rosas 10/15 Protocolo Knock Knock parte 1 public class KnockKnockProtocol { private static final int WAITING = 0; private static final int SENTKNOCKKNOCK = 1; private static final int SENTCLUE = 2; private static final int ANOTHER = 3; private static final int NUMJOKES = 5; private int state = WAITING; private int currentJoke = 0; private String[] clues = { "Turnip", "Little Old Lady", "Atch", "Who", "Who" }; private String[] answers = { "Turnip the heat, it's cold in here!", "I didn't know you could yodel!", "Bless you!", "Is there an owl in here?", "Is there an echo in here?" }; public String processInput(String theInput) { String theOutput = null; if (state == WAITING) { theOutput = "Knock! Knock!"; state = SENTKNOCKKNOCK; } else if (state == SENTKNOCKKNOCK) { if (theInput.equalsIgnoreCase("Who's there?")) { theOutput = clues[currentJoke]; state = SENTCLUE; } else { theOutput = "You're supposed to say \"Who's there?\"! " + "Try again. Knock! Knock!"; } Cecilia Curlango Rosas 11/15 Protocolo Knock Knock parte 2 } else if (state == SENTCLUE) { if (theInput.equalsIgnoreCase(clues[currentJoke] + " who?")) { theOutput = answers[currentJoke] + " Want another? (y/n)"; state = ANOTHER; } else { theOutput = "You're supposed to say \"" + clues[currentJoke] + " who?\"" + "! Try again. Knock! Knock!"; state = SENTKNOCKKNOCK; } } else if (state == ANOTHER) { if (theInput.equalsIgnoreCase("y")) { theOutput = "Knock! Knock!"; if (currentJoke == (NUMJOKES - 1)) currentJoke = 0; else currentJoke++; state = SENTKNOCKKNOCK; } else { theOutput = "Bye."; state = WAITING; } } return theOutput; } } Cecilia Curlango Rosas 12/15 public class KnockKnockClient { public static void main(String[] args) throws IOException { Socket kkSocket = null; PrintWriter out = null; BufferedReader in = null; try { kkSocket = new Socket("taranis", 4444); out = new PrintWriter(kkSocket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(kkSocket.getInputStream())); } catch (UnknownHostException e) { System.err.println("Don't know about host: taranis."); System.exit(1); } catch (IOException e) { System.err.println("Couldn't get I/O for the connection to: taranis."); System.exit(1); } BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); String fromServer; String fromUser; while ((fromServer = in.readLine()) != null) { System.out.println("Server: " + fromServer); if (fromServer.equals("Bye.")) break; fromUser = stdIn.readLine(); if (fromUser != null) { System.out.println("Client: " + fromUser); out.println(fromUser); } } out.close(); in.close(); stdIn.close(); kkSocket.close(); } } Cecilia Curlango Rosas 13/15 Ejercicios 1. Probar el servidor y el cliente en las máquinas del laboratorio. ¿Cómo debe modificarse el cliente? 2. Modificar el servidor para que utilice un puerto que se le asigne en el momento de la ejecución. No olividar publicar el número del puerto para que se pueda conectar el cliente. 3. Probar el cliente con el servidor de otro compañero. ¿Cómo debe modificarse el cliente? 4. ¿Cómo debe modificarse el servidor para atender a múltiples clientes simultáneamente? Cecilia Curlango Rosas 14/15 Referencias ● ● Aplicaciones cliente-servidor con sockets http://download.oracle.com/javase/tutorial/networking/sockets/clientServer.html Clase ServerSocket http://download.oracle.com/javase/7/docs/api/index.html?java/net/URLConnection.html ● Cecilia Curlango Rosas 15/15