El Pinger presentado es una aplicación que utiliza el UDP. El cliente envía paquetes UDP y el servidor los recibe y los retorna. Para descibir ambas partes se ha utilizado el lenguaje de programación Java.
El servidor es básicamente un bucle infinito que espera a recibir paquetes UDP. Para ello escucha en el puerto que se le indica por la línea de comandos cuando es ejecutado.
Como la mayoría de las ocasiones tendremos que ejecutar el cliente y el servidor en el mismo host, el servidor puede configurarse para:
Sin embargo, dentro del mismo host o incluso en la red de laboratorio, es prácticamente imposible que se pierdan paquetes. Para simular dicho comportamiento el servidor deja de enviar un eco al cliente con una cierta probabilidad controlada por el parámetro que llamado LOSS_RATE.
A continuación se presenta el código que implementa el servidor (http://www.ace.ual.es/ vruiz/docencia/redes/practicas/PingServer.java(:
import java.io.*;
import java.net.*; import java.util.*; /* * Un servidor que procesa peticiones ping sobre UDP. */ public class PingServer { private static final double LOSS_RATE = 0.3; private static final int AVERAGE_DELAY = 100; // milisegundos public static void main(String[] args) throws Exception { /* Comprobamos que se han introducido los parámetros de entrada desde la línea de comandos. */ if (args.length != 1) { System.out.println("You must specify a port"); return; } /* Puerto de escucha del servidor. */ int port = Integer.parseInt(args[0]); /* Usaremos un generador de números aleatorios para simular la * pérdida de paquetes y el retraso de la red. */ Random random = new Random(); /* Creamos un socket de tipo DatragramSocket para recibir y * enviar paquetes UDP. */ DatagramSocket socket = new DatagramSocket(port); /* Processing loop. */ while (true) { /* Creamos la estructura de datos que nos servirá para almacenar un paquete UDP. */ DatagramPacket request = new DatagramPacket(new byte[1024], 1024); /* Nos bloqueamos hasta que se recibe el siguiente paquete UDP. */ socket.receive(request); /* Imprimimos el payload del paquete. */ printData(request); /* Decidimos si responder o simular la pérdida del paquete. */ if (random.nextDouble() < LOSS_RATE) { System.out.println(" Reply not sent."); continue; } /* Simulamos el retraso de la red. */ Thread.sleep((int) (random.nextDouble() * 2 * AVERAGE_DELAY)); /* Enviamos la respuesta. */ InetAddress clientHost = request.getAddress(); int clientPort = request.getPort(); byte[] buf = request.getData(); DatagramPacket reply = new DatagramPacket(buf, buf.length, clientHost, clientPort); socket.send(reply); System.out.println(" Reply sent."); } } /* * Imprime los datos del datagrama (payload) sobre la salida estándar. */ private static void printData(DatagramPacket request) throws Exception { /* "buf" apunta al comienzo de los datos en el paquete. */ byte[] buf = request.getData(); /* Convertimos "buf" en un stream de entrada de bytes. */ ByteArrayInputStream bais = new ByteArrayInputStream(buf); /* Convertimos "bais" en un stream de entrada de caracteres. */ InputStreamReader isr = new InputStreamReader(bais); /* Convertimos "isr" en un stream de entrada de caracteres buffereado. Así podremos leer líneas completas. Una línea es cualquier combinación de caracteres que acaba en cualquier combinación de \r y \n. */ BufferedReader br = new BufferedReader(isr); /* Los datos del mensaje están contenidos en una única // línea. Así la leemos. */ String line = br.readLine(); /* Imprimimos la dirección del host que envía el mensaje y los // datos del mismo. */ System.out.println("Received from " + request.getAddress().getHostAddress() + ": " + new String(line) ); } } |
# Este comando genera el fichero "PingServer.class".
javac PingServer.java |
# Recuerde que hay que utilizar un puerto mayor que 1024
# si no somos el usuario root. # El fichero "PingServer.class" debería existir en el directorio actual. java PingServer 6789 |
El cliente envía 10 peticiones de ping al servidor especificado. Cada mensaje contiene un payload de datos donde figura la cadena PING, un número de secuencia y una estámpa de tiempo.
Tras enviar un paquete, el cliente espera hasta un segundo para recibir una respuesta. Si transcurrido este tiempo ésta no llega, el cliente supone que su paquete de petición o el paquete de respuesta se ha perdido.
A continuación se muestra el código del cliente (http://www.ace.ual.es/ vruiz/docencia/redes/practicas/Client.java):
import java.io.*;
import java.net.*; import java.util.*; /* * Un cliente que genera peticiones ping sobre UDP. */ public class PingClient { public static final String CRLF="\r\n"; public static void main(String[] args) throws Exception { /* Comprobamos que se han introducido los parámetros de entrada desde la línea de comandos. */ if (args.length != 2) { System.out.println("You must specify a server and a port"); return; } /* Obtenemos la dir IP del servidor a partir de su nombre. */ InetAddress serverAddress = InetAddress.getByName(args[0]); /* Obtenemos el puerto en el que escucha el servidor. */ int serverPort = Integer.parseInt(args[1]); /* Creamos un socket de tipo DatragramSocket para recibir y * enviar paquetes UDP. */ DatagramSocket socket = new DatagramSocket(); /* Asignamos un tiempo máximo de espera de recepción a través * de este socket (time-out) de un segundo. */ socket.setSoTimeout(1000); /* Creamos la estructura de datos que almacenará un paquete UDP. */ DatagramPacket reply = new DatagramPacket(new byte[1024], 1024); /* Enviamos los 10 paquetes. */ for (int i=0; i<10; ++i) { /* Generamos el payload del paquete con el instante en que * el mismo es generado. */ long sendingDate = (new Date()).getTime(); String payload = "Ping " + (i+1) + " " + sendingDate + CRLF; DatagramPacket request = new DatagramPacket(payload.getBytes(), payload.getBytes().length, serverAddress, serverPort); System.out.print("Packet sent with payload: " + payload); /* Envismos el paquete. */ socket.send(request); /* Esperamos la respuesta del servidor. */ try { socket.receive(reply); } catch(SocketTimeoutException e) { /* Se ha producido un time-out. */ System.out.println("Not response from server"); continue; } /* Calculamos el tiempo que el paquete ha tardado en regresar. */ long receivingDate = (new Date()).getTime(); System.out.println("Packet received after " + (receivingDate-sendingDate) + " miliseconds"); } } } |
javac PingClient.java
java PingClient localhost 6789 |