Redes Comandos Switch y Router Cisco v2 3
Redes Comandos Switch y Router Cisco v2 3
Redes Comandos Switch y Router Cisco v2 3
El curso está dividido en tres partes. Este material cubre la parte del curso relacionada
con la manipulación de herramientas informáticas y el desarrollo de aplicaciones.
Índice general
1. Introducción 2
1.1. Desarrollo de aplicaciones Informáticas . . . . . . . . . . . . . . . . . . . . . 2
1.2. Herramientas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.1. Proceso de Compilación . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.2. Compilación de programas formados por varios módulos . . . . . . . 5
1.2.3. Creación de Librerı́as . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.4. Documentación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.3. Lenguajes de Programación . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
4. Creación de Threads 20
4.1. La clase Thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.2. La interfaz Runnable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.3. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
5. Sincronización de Threads 23
5.1. Exclusión mutua y secuencialización . . . . . . . . . . . . . . . . . . . . . . 23
5.2. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1
Herramientas y Lenguajes de Programación 05-06 2
7.4. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Introducción
El principal objetivo de está parte del curso de doctorado es dotar al alumno de las
habilidades necesarias para la manipulación de herramientas informáticas que le permitan
realizar una labor investigadora eficaz.
En el desarrollo de un proyecto informático uno de los aspectos más importantes es
la elección del lenguaje más apropiado para su implementación y las herramientas a uti-
lizar. Existen múltiples herramientas informáticas y múltiples lenguajes de programación
dependiendo del área de estudio. Una vez elegido el lenguaje, se ha de recabar información
sobre las herramientas disponibles y realizar un estudio acerca de cuál se adapta mejor
a las necesidades del proyecto a realizar. Ası́ pues, es necesario iniciar al alumnado en el
desarrollo sistemático y ordenado de aplicaciones informáticas integradas en proyectos de
investigación. En este curso, se especifican de forma genérica las fases que componen el
desarrollo e implementación de una aplicación informática y se formalizan las mismas con
ejemplos concretos de realización.
Los objetivos concretos del curso son:
Manejar los fundamentos básicos del sistema operativo UNIX (Linux).
Conocer las herramientas informáticas UNIX (Linux) fundamentales para el desar-
rollo de aplicaciones.
Comprender los principios básicos de la programación imperativa, y oritentada a
objetos.
Reconocer la importacia de la generación de documentación que acompaña a todo
proyecto informático.
Comprender como diseñar algoritmos eficientes utilizando distintas técnicas algorı́tmi-
cas.
3
Herramientas y Lenguajes de Programación 05-06 4
4. Compilar el programa.
Aunque las etapas se presentan de forma secuencial, es habitual cometer errores que
provoquen el tener que regresar a fases anteriores. El esquema que se muestra en la Figura
1.1 es válido para programas no demasiado complejos. Para los grandes proyectos in-
formáticos exite un conjunto de técnicas de desarrollo que pueden estudiarse en cualquier
libro de Ingenierı́a del Software, por ejemplo, R.S. Pressman, Ingenierı́a del Software: Un
enfoque Prático, McGraw-Hill, 4 edición, 1998. ISBN 84-481-1186-9.
1.2. Herramientas
En el desarrollo de un proyecto informático un aspecto importante es qué tipo de her-
ramientas se han de utilizar y el lenguaje más apropiado para su implementación. Existen
Herramientas y Lenguajes de Programación 05-06 5
Preprocesamiento
Enlace ( linker )
g++ -c programa1.c
g++ -c programa2.c
g++ programa1.o programa2.o
sus miembros. Cuando se añade un fichero a una librerı́a, los datos de éste y su informa-
ción administrativa (permisos, fechas, propietario, grupo, etc.) se introduce en él. Para
una descripción detallada de las opciones de esta herrmienta visite la página de manual
(man ar).
Las funciones básicas de ar son: crear, modificar y extraer miembros.
Entre las opciones se deben distinguir aquellas que son obligatorias y los modificadores.
Cuando se emite una orden ar es necesario que haya una obligatoria y sólo una.
Los paquetes Java agrupan las clases en librerı́as (bibliotecas). Los paquetes Java se
utilizan de forma similar a como se utilizan las librerı́as en C++, sólo que en Java se
agrupan clases y/o interfaces.
En los paquetes las clases son únicas, comparadas con las de otros paquetes, y per-
miten controlar el acceso. Esto es, los paquetes proporcionan una forma de ocultar clases,
evitando que otros programas o paquetes accedan a clases que son de uso exclusivo de una
aplicación determinada.
Los paquetes se declaran utilizando la palabra reservada package seguida del nombre
del paquete. Esta sentencia debe estar al comienzo del fichero fuente. Concretamente debe
ser la primera sentencia ejecutable del código Java, excluyendo, los comentarios y espacios
en blanco. Por ejemplo:
package figuras;
public class Circulo {
. . .
}
En este caso, el nombre del paquete es figuras. La clase Circulo se considera como
parte del paquete. La inclusión de nuevas clases en el paquete es simple, se ha de colocar
la misma sentencia al comienzo de los ficheros que contengan la declaración de las clases.
Cada uno de los ficheros que contengan clases pertenecientes a un mismo paquete, deben
incluir la misma sentencia package, y solamente puede haber una sentencia package por
fichero. La sentencia package colocada el comienzo de un fichero fuente afectará a todas
las clases que se declaren en ese fichero.
Se pueden referenciar paquetes precediendo con su nombre la clase que se quiere usar.
También se puede usar la palabra reservada import, si se van a colocar múltiples referencias
a un mismo paquete.
La sentencia import se utiliza para incluir una lista de paquetes en los que buscar una
clase determinada, y su sintaxis es:
import nombre_paquete.Nombre_Clase;
Esta sentencia, o grupo de ellas, deben aparecer antes de cualquier declaración de clase
en el código fuente.
Herramientas y Lenguajes de Programación 05-06 9
1.2.4. Documentación
La herramienta javadoc genera páginas HTML de documentación del API a partir de
ficheros con código fuente Java.
En la lı́nea de comandos se le puede pasar a javadoc una serie de paquetes o ficheros
Java para los que se desea generar documentación. Se genera documentación para el pa-
quete especificado o para los ficheros fuentes Java individuales que se listen en la lı́nea de
comandos. Se genera un fichero .html por cada fichero .java que se encuentre. También
se genera la jerarquı́a de clases (tree.html) y un ı́ndice con todos los miembros que ha
detectado (AllNames.html).
La utilidad javadoc extrae información de los siguiente elementos:
Paquetes
/**
* Este es un comentario de documentación
*/
@see java.lang.String
@see String
@see String#equals
@see java.lang.Object#waint(int)
@see Character#MAX_RADIX
@see <a href="spec.html">Especif. Java</a>
Se utiliza el carácter # para separar el nombre de una clase del nombre de uno de
sus campos de datos, métodos o constructores.
@version texto-version
Añade una entrada “Version”. El texto no tiene que tener formato especial.
@author texto-autor
Añade una entrada “Author”. El texto no tiene que tener formato especial.
@since texto
Este texto no tiene una estructura especial. Se utiliza para indicar desde qué fecha
o desde qué versión se ha introducido el cambio o caracterı́stica que indica el texto.
@deprecated texto
/**
* Clase que representa la figura geométrica cilindro
* Por ejemplo:
* <PRE>
* Cilindro c = new Cilindro(1.0);
* double d = c.volumen();
* </PRE>
*
* @see figuras.Circulo
* @see figuras.ObjetoGeometrico
* @version 1.5 14 Mar 04
* @author Coromoto Leon Hernandez
*/
public class Cilindro extends Circulo {
. . .
}
Herramientas y Lenguajes de Programación 05-06 11
/**
* El palo de bastos
*/
public static final int BASTOS = 1;
Añade una sección “Return”, que debe contener la descripción del valor a devolver.
@throws exception descripcion
Añade una entrada “Throws”, que contiene el nombre de la excepción que puede
ser lanzada por el método. La excepción estará enlazada con su clase en la docu-
mentación.
@see nombre_de_clase
Indica desde qué fecha o desde qué versión se ha introducido el cambio o caracterı́stica
que indica el texto.
@deprecated texto
Indica que no deberı́a utilizarse el método, porque está desautorizado y puede dejar
de ser soportado por el API en cualquier momento. Ejemplo de comentario de un
método:
/**
* Devuelve el carácter de la posición indicada entre
* <tt>0</tt> y <tt>length()-1</tt>
* @param indice La posición del carácter a obtener
* @return El carácter situado en la posición
Herramientas y Lenguajes de Programación 05-06 12
* @exception StringIndexOutOfRangeException
* Se prodcue cuando el indice no está en
* el rango <tt>0</tt> a <tt>length()-1</tt>
*/
public char charAt( int indice ) {
. . .
}
Si dos subprogramas comparten una misma función f n reutilizando ası́ el código que
define la misma, y más adelante queremos modificar f n porque hay un cambio en
uno de los subprogramas que la utilizan, la modificación afectará también al otro
subprograma, razón por la que ahora tendremos que realizar dos funciones.
programa?. Ası́ que el desarrollo se organiza en torno a los datos y no a como se debe
funcionar.
En la programación orientada a objetos, un programa es una colección de una sóla
entidad básica, el objeto, el cual combina los datos con los procedimientos que actúan
sobre ellos. Durante la ejecución los objetos reciben y envı́an mensajes a otros objetos
para ejecutar las acciones requeridas.
La programación orientada a objetos se puede llevar a cabo con lenguajes conven-
cionales, pero esto exige al programador la construcción de los mecanismos de que dispo-
nen los lenguajes orientados a objetos, tales como: objetos, clases, métodos, mensajes,
herencia. etc.
Herramientas y Lenguajes de Programación 05-06 14
Capı́tulo 2
1 /**
2 * Applicacion Simple
3 */
4 class AplicacionSimple {
5 public static void main(String[] args) {
6 System.out.println("Hola Mundo en Java");
7 }
8 }
El primer paso para manipular una aplicación Java es compilarla ejecutando en la lı́nea
de comandos la instrucción
>javac AplicacionSimple.java
Es importante que el nombre del fichero que contiene el código coincida exactamente
con el nombre de la clase que aparece en la lı́nea número 3.
Al realizar este paso se obtiene un fichero AplicacionSimple.class.
Para ejecutar la aplicación escribimos en la lı́nea de comandos
>java AplicacionSimple
15
Herramientas y Lenguajes de Programación 05-06 16
2.2. Ejercicios
1. Compile y ejecute el ejemplo de aplicación.
(conexión a java.sun.com )
Ejecute el comando javadoc desde la lı́nea de comandos sin ningún argumento y
obtendrá una lista de las opciones con las que puede llamar a la herramienta.
Herramientas y Lenguajes de Programación 05-06 17
Nótese que para que aparezcan en el fichero html los comentarios asociados a los
campos de datos privados, tiene que compilarlos con la opción -private.
De la misma forma, para que aparezcan el autor y la versión, se han de utilizar las
opciones -author y -version.
Capı́tulo 3
/**
* Applet Sencillo
*/
import java.applet.Applet;
import java.awt.Graphics;
>javac AppletSimple.java
18
Herramientas y Lenguajes de Programación 05-06 19
El siguiente código html contine la estructura de la etiqueta para el ejemplo que nos
ocupa (está almacenado en un fichero con nombre html.html).
<html>
<head>
<title> Un applet simple </title>
</head>
<body>
<p>
A continuación está la salida del programa
</p>
<applet code="AppletSimple.class" width="300" height="100">
No hay disponible un intérprete de Java
</applet>
</body>
</html>
>appletviewer html.html
3.2. Ejercicios
1. Compile y ejecute el ejemplo de applet.
Creación de Threads
El objetivo de esta práctica es introducir al uso de los threads (hilos) y trabajar con
las clases que permiten su creación.
En una clase cliente se crea un objeto thread . A estos objetos se les denomina “objetos
ejecutables”. El método start() le indica al sistema que el thread está listo para ejecutarse.
21
Herramientas y Lenguajes de Programación 05-06 22
Declarar un objeto Thread en la clase destino. Por ejemplo, las siguientes sentencias
declaran una instancia de la clase Thread, t, con valor inicial nulo:
Por defecto, el valor inicial es nulo, ası́ que la asignación al valor “null”no es necesaria.
4.3. Ejercicios
1. Escriba una aplicación Java que implemente lo siguiente:
Productor Consumidor
Mostrador
Sincronización de Threads
El objetivo de esta práctica es trabajar con los principios básicos de los threads (hilos):
la sincronización y la secuencialización.
3. El thread B recibe un valor y luego accede a contador de nuevo antes de que A haya
generado un nuevo valor. Se utiliza dos veces el valor antiguo.
24
Herramientas y Lenguajes de Programación 05-06 25
El escenario 1 requiere exclusión mutua, en que no permite que dos threads tengan
acceso simultáneo al recurso compartido contador. Los escenarios 2 y 3 requieren secuen-
cialización, en que cada thread debe esperar a que el otro termine de usar el recurso
compartido.
Es importante señalar que estos escenarios son problemáticos sólo porque los threads A
y B tienen acceso al objeto contador. Si el código que ejecutan A y B no hiciera referencia
a un objeto compartido, estos subprocesos podrı́an ejecutarse en el orden que decida el
Sistema Operativo y dicho orden no tendrı́a efecto en el resultado del programa.
La aplicación PCTest.java contiene la definición de una aplicación Productor/Con-
sumidor en la que se instancian dos objetos: uno de tipo Productor y otro de tipo
Consumidor. Estos objetos son threads que se encargan uno de poner un valor y el otro de
recogerlo de un objeto de tipo Mostrador. El Productor genera enteros entre 0 y 9, los
almacena en el mostrador y los imprime. El Consumidor al contrario, consume todos los
enteros del mostrador (que es exactamente el mismo objeto en el que el productor coloca
los enteros) tan pronto como están disponibles. Ası́ pues, el productor y el consumidor de
este ejemplo comparten los datos a través del objeto de tipo Mostrador.
5.2. Ejercicios
1. Compile y ejecute la aplicación Productor/Consumidor.
2. Añada al código de la aplicación Productor/Consumidor las sentencias necesarias
para que los dos threads que se ejecutan pasen al estado de dormido durante un
intervalo aleatorio de tiempo. ¿Cambia el resultado de la ejecución? ¿Por qué?
3. Implemente los cambios necesarios para que el programa admita la creación de más
de un thread productor y más de un thread consumidor. Ejecute el nuevo progra-
ma lanzando varios productores y varios consumidores. Dibuje el diagrama de la
ejecución (métodos × tiempo).
4. Añada los cambios necesarios al applet que se ha desarrollado en prácticas anteriores
para que tenga el mismo funcionamiento que la aplicación Productor/Consumidor.
Además:
El Productor generará los enteros impares sucesivos y los colocará en el campo
de texto compartido.
El Consumidor ha de recoger los valores del campo de texto y sumarlos.
El Productor indica el final de su tarea colocando el valor “-1” en el campo de
texto, mientras que el Consumidor utiliza el “-1” como señal para informar de
la suma.
Finalmente cuando el usuario hace click en el botón del applet se lanzan los
threads.
Dibuje el diagrama de la ejecución (métodos × tiempo).
Capı́tulo 6
Direcciones IP y Nombres de
Dominio
Ejemplo
El ejemplo TestInetAddress.java trata de ilustrar la utilización de varios de los méto-
dos de la clase InetAddress. Para que el programa se ejecute correctamente y no aparezca
una excepción del tipo “UnknownHostException”, hay que estar conectados conveniente-
mente. En caso de conectarse a un proveedor de Internet, la asignación de direcciones es
automática por parte del ISP (Internet Service Provider ), con lo cual se va a obtener una
dirección diferente en cada conexión.
import java.net.*;
class TestInetAddress {
public static void main( String[] args ) {
try {
System.out.println( "-> Direccion IP de una URL, por nombre" );
InetAddress address = InetAddress.getByName( "nereida.deioc.ull.es" );
System.out.println( address );
26
Herramientas y Lenguajes de Programación 05-06 27
6.2. Ejercicios
1. Compile y ejecute el ejemplo TestInetAddress.
7.1. Introducción
Las redes actuales utilizan el packet switching para la transferencia de datos. Los datos
se envuelven en paquetes que se transfieren desde un origen a un destino, donde se extraen
de uno en uno los datos de uno o más paquetes para reconstruir el mensaje original.
Los nodos que se comunican a través de Internet utilizan principalmente dos protocolos:
29
Herramientas y Lenguajes de Programación 05-06 30
Figura 7.1:
destino usando un socket (una referencia indirecta a un puerto particular usada por el
proceso receptor en la máquina receptora).
Un datagrama enviado mediante udp es trasmitido desde un proceso emisor a un
proceso receptor sin reconocimiento o recomprobaciones. Si tiene lugar un fallo, el mensaje
puede no llegar. Un datagrama es transmitido entre procesos cuando un proceso lo envı́a
y otro proceso lo recibe. Cualquier proceso que necesite enviar o recibir mensajes debe en
primer lugar crear un socket a un dirección de Internet y a un puerto local. Un servidor
enlazará ese socket a un puerto servidor - uno que se hace conocido a los clientes de manera
que puedan enviar mensajes al mismo. Un cliente enlaza su socket a cualquier puerto local
libre. El método receptor devuelve la dirección de Internet y el puerto del emisor, además
del mensaje, permitiendo a los receptores enviar una respuesta.
Las clases Java para establecer comunicaciones mediante datagramas son: Datagram-
Packet y DatagramSocket.
array de bytes que contiene el mensaje longitud del mensaje dirección Intenet número de puerto
Los objetos del tipo DatagramPacket se pueden transmitir entre procesos cuando un
proceso los envı́a y otro los recibe.
Esta clase proporciona otro constructor para usarlo cuando se recibe un mensaje. Sus
argumentos especifican un array de bytes en el que recibir el mensaje y la longitud del
array. Cuando se recibe un mensaje se pone en el DatagramPacket junto con su longitud,
la dirección de Internet y el puerto del socket de envı́o.
Se puede obtener el mensaje del objeto DatagramPacket mediante el método getData().
Los métodos getPort() y getAddress() permiten obtener el puerto y la dirección Internet
del objeto de tipo DatagramPacket.
Herramientas y Lenguajes de Programación 05-06 31
El proceso receptor del mensaje tiene que especificar un array de bytes de un tamaño
determinado en el cual recibir el mensaje, esto es, ha de predecir el Tamaño del Mensaje. Si
el mensaje es muy grande para el array se trunca cuando llega. El protocolo ip subyacente
permite longitudes de paquetes de más de 216 bytes, que incluye tanto las cabeceras como
los mensajes. Sin embargo, la mayorı́a de los entornos imponen una restricción en el tamaño
a 8 kilobytes. Cualquier aplicación que necesite mensajes mayores que el máximo, debe
fragmentarlos en pedazos de ese tamaño. Generalmente, una aplicación decidirá sobre un
tamaño que no sea excesivamente grande pero que se adecue a su uso previsto.
send() y receive().
Estos métodos permiten transmitir datagramas entre un par de sockets. El argu-
mento del send es una instancia de un DatagramPacket que contiene un mensaje
y su destino. El argumento del receive es un objeto DatagramPacket vacı́o en el
cual se pondrá el mensaje, su longitud y su origen. Tanto el método send() como el
receive() pueden lanzar una IOException.
Las comunicaciones mediante datagramas de udp usan envı́os no bloqueantes (non-
blocking sends) y recepciones bloqueantes (blocking receives). Las operaciones de
envı́o retornan cuando estas han dado el mensaje a los protocolos ip o udp suby-
acentes, los cuales son responsables de trasmitirlos a su destino. En la llegada, el
mensaje es puesto en una cola por el socket que está asociado al puerto de destino.
El mensaje puede ser recogido de la cola por una excepción o llamadas futuras de
recepcion (receive()) sobre ese socket. Los mensajes son descartados en el des-
tino si ningún proceso tiene asociado un socket al puerto de destino. El método
receptor (receive()) se bloquea hasta que se recibe un datagrama, a menos que
se establezca un tiempo lı́mite (timeout) sobre el socket. Si el proceso que invoca
al método receive() tiene otra tarea que hacer mientras espera por el mensaje,
deberı́a planificarse en un flujo de ejecución (thread ) separado.
setSoTimeout().
Este método permite establecer un tiempo de espera. Con un tiempo de espera
establecido, el método receive() se bloqueará por el tiempo especificado y entonces
lanzará una InterruptedIOException().
Herramientas y Lenguajes de Programación 05-06 32
connect().
Este método se utiliza para conectar a un puerto remoto particular y una dirección
de Internet, en este caso el socket sólo es capaz de enviar y recibir mensajes desde
esa dirección.
7.4. Ejercicios
El siguiente código utiliza sockets datagrama para intercambiar una única cadena de
datos. La lógica del programa es lo más sencilla posible para subrayar la sintáxis básica
de las comunicaciones entre procesos. El emisor crea un paquete datagrama que contiene
una dirección de destino, mientras que el paquete datagrama del receptor no incluye una
dirección de destino.
import java.net.*;
import java.io.*;
import java.net.*;
import java.io.*;
1. Compile y ejecute el código del ejemplo en una máquina usando “localhost” como
nombre de máquina. Por ejemplo se puede introducir el comando:
java Example1Sender localhost 12345 Hola
Ejecute los dos programas arrancando primero al receptor y después al emisor. El
mensaje que se envı́e no deberı́a exceder la longitud máxima permitida que es de 10
caracteres.
Describa el resultado de la ejecución.
3. Vuelva a ejecutar las aplicaciones del apartado 1, esta vez ejecutando primero al
emisor y luego al receptor.
Describa y explique el resultado.
4. Repita el apartado 1, esta vez mandando un mensaje de longitud más grande que la
máxima longitud permitida.
Describa y explique la salida producida.
Herramientas y Lenguajes de Programación 05-06 34
5. Añada código al proceso receptor de manera que el plazo máximo de bloqueo del
receive sea de cinco segundos. Lance el proceso receptor pero no el proceso emisor.
¿Cuál es el resultado? Descrı́balo y explı́quelo.
lance al receptor
ejecute el emisor enviando un mensaje “mensaje 1”
en otra ventana, lanzar otra instancia del emisor, mandando un mensaje “men-
saje 2”.
7. Modifique el código original de manera que el emisor utilice el mismo socket para
enviar el mismo mensaje a dos receptores diferentes. Primero lance los dos recep-
tores y después al emisor. ¿Cada receptor recibe el mensaje? Describa y explique el
resultado.
8. Modifique el código original de manera que el emisor utilice dos socket distintos
para enviar el mismo mensaje a dos receptores diferentes. Primero lance los dos
receptores y después al emisor. ¿Cada receptor recibe el mensaje? Describa y explique
el resultado.
9. Modifique el código del último paso de modo que el emisor envı́e de forma perma-
nente, suspendiéndose durante 3 segundos entre cada envı́o.
Modifique el receptor de manera que ejecute un bucle que repetidamente reciba datos
y luego los muestre.
Compile y ejecute los programas durante unos cuentos segundos antes de teminarlos
con “Ctrl-C”.
Describa y explique el resultado.
10. Modifique el código original de modo que el emisor también reciba un mensaje del
receptor. Utilizar sólo un socket en cada proceso. Entregue este código.
Capı́tulo 8
8.1. Introducción
El paradigma Cliente/Servidor es quizás el más conocido de los paradigmas para apli-
caciones de red. Se usa para describir un modelo de interacción entre dos procesos, que
se ejecutan de forma simultánea. Este modelo es una comunicación basada en una serie
de preguntas y respuestas, que asegura que si dos aplicaciones intentan comunicarse, una
comienza la ejecución y espera indefinidamente que la otra le responda y luego continua
con el proceso.
35
Herramientas y Lenguajes de Programación 05-06 36
Los procesos clientes son más sencillos que los procesos de los servidores, los primeros
no requieren de privilegios de sistemas para funcionar, en cambio los procesos servidores
sı́.
Los usuarios cuando quieren acceder a un servicio de red, ejecutan un software cliente.
El diseño de los servidores debe ser muy cuidadoso, debe incluir código para la manipu-
lación de:
protección: asegurar que las aplicaciones no monopolicen los recursos del sistema.
Un único servidor tı́picamente sirve a una multitud de clientes, ahorrando a cada uno
de ellos el problema de tener la información instalada y almacenada localmente.
8.2. Sockets
Normalmente, un servidor se ejecuta en una máquina especı́fica y tiene un socket aso-
ciado a un número de puerto especı́fico. El servidor simplemente espera a la escucha en
el socket a que un cliente se conecte con una petición. El cliente conoce el nombre de la
Herramientas y Lenguajes de Programación 05-06 37
máquina sobre la que está ejecutándose el servidor y el número de puerto al que está conec-
tado. Solicitar una conexión consiste en intentar establecer una cita con el servidor en el
puerto de la máquina servidora.
Si todo va bien, el servidor acepta la conexión. Pero antes, el servidor crea un nuevo
socket en un puerto diferente. Es necesario crear un nuevo socket (y consecuentemente un
número de puerto diferente) de forma que en el socket original se continue a la escucha de
las peticiones de nuevos clientes mientras se atiende a las necesidades del cliente conectado.
En el cliente, si se acepta la conexión, el socket se crea satisfactoriamente y se puede utilizar
para comunicarse con el servidor.
Ejemplo 1
remota, esperando cualquier tráfico de red que “hable con él ”en el puerto 13. Cuando el
Sistema Operativo de este servidor recupera un paquete de red que contiene una petición
para conectar con el puerto 13, activa el servicio de escucha del servidor y establece la
conexión, que permanece activa hasta que es finalizada por alguna de las dos partes.
import java.net.*;
import java.io.*;
import java.util.*;
class ClienteFecha {
public static void main( String[] args ) {
String servidor = "localhost";
int puerto = 13; // puerto de daytime
try {
// Se abre un socket conectado al servidor y al
// puerto estándar de echo
Socket socket = new Socket( servidor,puerto );
System.out.println( "Socket Abierto." );
// Se cierra el socket
socket.close();
} catch( UnknownHostException e ) {
System.out.println( e );
System.out.println(
"Debes estar conectado para que esto funcione bien." );
} catch( IOException e ) {
System.out.println( e );
}
}
}
Ejemplo 2
import java.io.*;
import java.net.*;
try {
echoSocket = new Socket(serverName, portNumber);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader( echoSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don’t know about host: " + serverName);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn’t get I/O for " + "the connection to: " + serverName);
System.exit(1);
}
out.close();
in.close();
stdIn.close();
echoSocket.close();
}
}
Ejemplo
Este ejemplo muestra cómo escribir un servidor y su cliente. Está sacado del Tutorial
de Java de Sun. El servidor sirve chistes. Funciona de la siguiente forma:
Herramientas y Lenguajes de Programación 05-06 40
while (true) {
Socket incoming = s.accept();
Ejemplo
Este ejemplo amplı́a al de la sección anterior mostrando cómo escribir un servidor que
atiende a múltiples clientes. El modo de funcionamiento es exactamente el mismo.
El ejemplo consta de dos programas Java ejecutándose de forma independiente Knock-
KnockClient y KKMultiServer. Para probarlo en una terminal lance al servidor, y en
dos o más nuevas terminales lance a varios clientes. La aplicación está constituida por los
siguientes ficheros:
8.4. Ejercicios
1. Modificar el ejemplo Cliente de Eco del enunciado de manera que:
Solución:
EchoClient.java
Herramientas y Lenguajes de Programación 05-06 42
import java.net.*;
import java.io.*;
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?" };
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!";
}
} 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;
Herramientas y Lenguajes de Programación 05-06 44
else
currentJoke++;
state = SENTKNOCKKNOCK;
} else {
theOutput = "Bye.";
state = WAITING;
}
}
return theOutput;
}
}
import java.io.*;
import java.net.*;
try {
kkSocket = new Socket("localhost", 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: manis.csi.ull.es.");
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn’t get I/O for the connection to: manis.csi.ull.es.");
System.exit(1);
}
fromUser = stdIn.readLine();
if (fromUser != null) {
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
}
out.close();
in.close();
stdIn.close();
kkSocket.close();
}
}
Herramientas y Lenguajes de Programación 05-06 45
import java.net.*;
import java.io.*;
outputLine = kkp.processInput(null);
out.println(outputLine);
import java.net.*;
import java.io.*;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(-1);
}
while (listening)
new KKMultiServerThread(serverSocket.accept()).start();
serverSocket.close();
}
}
import java.net.*;
import java.io.*;
out.close();
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}