0% encontró este documento útil (0 votos)
6 vistas18 páginas

Introducción a Redes y Sockets en Java

El documento presenta una introducción a la comunicación en redes utilizando Java, explicando conceptos básicos como TCP, UDP, puertos y clases relevantes del paquete java.net. Se incluyen ejemplos de código para trabajar con URLs, sockets y datagramas, así como ejercicios prácticos para reforzar el aprendizaje. Además, se discute la implementación de un servidor web y un servidor de datagramas, destacando la diferencia entre la comunicación basada en conexión y la comunicación sin conexión.
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
6 vistas18 páginas

Introducción a Redes y Sockets en Java

El documento presenta una introducción a la comunicación en redes utilizando Java, explicando conceptos básicos como TCP, UDP, puertos y clases relevantes del paquete java.net. Se incluyen ejemplos de código para trabajar con URLs, sockets y datagramas, así como ejercicios prácticos para reforzar el aprendizaje. Además, se discute la implementación de un servidor web y un servidor de datagramas, destacando la diferencia entre la comunicación basada en conexión y la comunicación sin conexión.
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Introducción a esquemas de nombres, redes,

clientes y servicios con Java


Luis Daniel Benavides Navarro
Escuela Colombiana de Ingenierı́a
Arquitectura Empresarial
20 de agosto de 2020

1. Reconocimiento
Parte de los contenidos y códigos de este taller están basados en los conte-
nidos de los tutoriales de Java que se encuentran en:
[Link]

2. Conceptos básicos de redes


Los programas que se comunican a través de internet utilizan generalmente
dos protocolos: el Transmission Control Protocol (TCP) o el User Datagram
Protocol (UDP). En java en general usted utiliza clases ya implementadas en el
paquete [Link].

2.1. TCP
El Transmission Control Protocol (TCP) es un protocolo basado en conexión
que provee una conexión confiable entre dos computadores. TCP en particular
mantiene el orden de los paquetes de datos y garantiza que todos los datos se
entreguen.

2.2. UDP
El User Datagram Protocol (UDP) es un protocolo que envı́a los datos en
paquetes llamados datagramas, no provee garantı́a de entrega ni de orden de
entrega. Este protocolo no esta basado en conexión.

2.3. Que son los puertos


En general los computadores tiene una sola conexión a internet y todos los
datos que llegan y salen utilizan esta conexión fı́sica. Sin embargo, el computador

1
puede tener múltiples aplicativos que utilizan la red. Para separar la información
que es enviada a una aplicativo especı́fico se asigno un número lógico a cada
aplicación. Este número es denominado el puerto y , como veremos más ade-
lante, es utilizado para enviar datos a aplicaciones especı́ficas en computadores
remotos.
Los protocolos de TCP y UDP utilizan estos puertos para enviar los datos
que llegan a las aplicaciones correctas. Recuerde que cada aplicación que espera
datos de la red se le asigna un puerto para que puede escuchar los datos que
llegan a un puerto determinado.
Los puertos se representan con un entero de 16 bits y tienen un rango de
0 hasta 65.535. Los puertos de 0- 1023 están restringidos para aplicaciones es-
pecı́ficas por ejemplo el 80 es para el servidor web.

2.4. Clases que soportan el trabajo con redes en Java


Algunas de las clases que utilizan TCP en Java son: URL, URLConnection,
Socket y ServerSocket. Todas están en el paquete [Link].
Algunas de las clases que utilizan UDP en Java son:DatagramPacket, Data-
gramSocket y MulticastSocket . Todas están en el paquete [Link].

3. Trabajando con URLs


URL es la abreviación de Uniform Resource Locator, y es básicamente una
dirección para localizar recursos en internet. Una idea clara de como son las
URLs la encontramos en nuestro navegador de internet. Ası́, la forma general
de una URL es la siguiente:
<protocolo>://<servidor>:<puerto>/<dirección del recurso en el servidor>
un ejemplo concreto es:
[Link]
En java se puede crear un URL de varias maneras:
URL personalSite = new URL("[Link]
Este código crea un objeto de tipo URL que lo asigna a la variable personalSite.
También puede crear una URL relativa a otra de la siguiente manera:
URL misPublicaciones = new URL(personalSite, "publications_bib.html");
Todos los constructores de la URL lanzan excepciones MalformedURLEx-
ception, por lo que es necesario colocarlos dentro de un bloque try-catch.
try {
URL myURL = new URL(. . .)
} catch (MalformedURLException e) {
[Link]();
}

2
1 import [Link].*;
import [Link].*;
3
public class URLReader {
5
public static void main(String[] args) throws Exception {
7 URL google = new URL("[Link]

9 try (BufferedReader reader


= new BufferedReader(new InputStreamReader([Link]()))) {
11 String inputLine = null;
while ((inputLine = [Link]()) != null) {
13 [Link](inputLine);
}
15 } catch (IOException x) {
[Link](x);
17 }
}
19 }

Figura 1: clase que lee datos de internet

3.1. Leyendo los valores de un objeto URL


El programador puede usar varios métodos para leer la información de un
objeto URL: getProtocol, getAuthority, getHost, getPort, getPath, getQuery,
getFile, getRef.

EJERCICIO 1
Escriba un programa en el cual usted cree un objeto URL e imprima en
pantalla cada uno de los datos que retornan los 8 métodos de la sección anterior.

3.2. Leyendo páginas de internet


Para leer páginas de internet debe crear flujos de datos (streams) y leer como
si lo hiciera del teclado. El ejemplo siguiente lee datos de internet y los presenta
en la pantalla (fig. 1).

3.3. Leyendo el encabezado de páginas de internet


Para continuar nuestra investigación de la arquitectura de internet y de
aplicaciones distribuidas debemos ahora intentar leer los encabezados de las
respuestas de los servidores web. Para esto, puede utilizar el código que se
muestra en la figura 2. El código crea primero un objeto URL y a partir de este
crea un objeto de tipo URLConnection. Desde el objeto urlConnection obtiene
el mapa de los encabezados. Este mapa lo recorre y lo presenta en pantalla.
Observe que, en la última lı́nea del código, el flujo de datos ya no se obtiene del
objeto URL sino del objeto de tipo URLConnection.

3
// Crea el objeto que representa una URL
2 URL siteURL = new URL(site);

4 // Crea el objeto que URLConnection


URLConnection urlConnection = [Link]();
6 // Obtiene los campos del encabezado y los almacena en un estructura Map
Map<String, List<String>> headers = [Link]();
8 // Obtiene una vista del mapa como conjunto de pares <K,V>
// para poder navegarlo
10 Set<[Link]<String, List<String>>> entrySet = [Link]();

12 // Recorre la lista de campos e imprime los valores


for ([Link]<String, List<String>> entry : entrySet) {
14 String headerName = [Link]();
//Si el nombre es nulo, significa que es la linea de estado
16 if(headerName !=null){[Link](headerName + ":");}
List<String> headerValues = [Link]();
18 for (String value : headerValues) {
[Link](value);
20 }
[Link]("");
22 //[Link]("");
}
24
[Link]("-------message-body------");
26 BufferedReader reader =
new BufferedReader(new
28 InputStreamReader([Link]()));
. . .

Figura 2: Código que lee datos del encabezado de la respuesta

EJERCICIO 2
Escriba una aplicación browser que pregunte una dirección URL al usuario
y que lea datos de esa dirección y que los almacene en un archivo con el nombre
[Link].
Luego intente ver este archivo en el navegador.

4. Sockets (enchufes)
Los sockets son los puntos finales del enlace de comunicación entre dos pro-
gramas ejecutándose en la red. Cada socket esta vinculado a un puerto especı́fico,
ası́ la capa que implementa el protocolo TCP puede saber a que aplicación en-
viar los mensajes. En general un servidor es un proceso que se ejecuta y tiene
un socket, vinculado a un puerto, que esta esperando solicitudes de clientes ex-
ternos. Los sockets son una abstracción de más bajo nivel que las URLs y sirven
para implementar protocolos de comunicación cliente-servidor.
El protocolo cliente servidor consiste en un programa cliente que hace soli-
citudes a un programa servidor que atiende dichas solicitudes.
Java provee dos clases para manejar la comunicación por medio de sockets:
Socket y ServerSocket. Ambas clases se encuentran en el paquete [Link].
NOTA: Una idea clara para entender los sockets es imaginar que son los

4
enchufes donde se conectan las aplicaciones para comunicarse.

4.1. Como usar los sockets desde el cliente


Vamos a utilizar sockets para crear un pequeño aplicativo cliente servidor. El
aplicativo consiste en un cliente que envı́a mensajes y un servidor que responde
con el mismo mensaje pero con una cadena “Respuesta:” al principio del mismo.
El servidor también imprime en pantalla los mensajes que recibe.
Antes de ver el código del cliente es importante ver que para obtener una
conexión se usa el código:
miSocket = new Socket("[Link]", 35000);
donde “[Link]” es el host local y 35000 es el puerto. Estas sentencias tienen
que estar rodeadas de bloque try-catch, para capturar los errores de conexión.
Una vez tenga la conexión, puede obtener flujos (Streams) de entrada y
salida utilizando
out = new PrintWriter([Link](), true);
in = new BufferedReader(new InputStreamReader(
[Link]()));
Una vez tenga los streams, puede enviar solicitudes y recibir las respuestas.
No olvide cerrar los sockets y los flujos. La figura 3 muestra el código del cliente.

4.2. Como utilizar los sockets desde el servidor


La siguiente parte consiste en implementar el servidor. El servidor escucha
en un puerto y responde a las solicitudes de cada cliente.
La figura 4 tiene el código del servidor. Este servidor responde el mismo
mensaje que recibe.

4.3. Ejercicios
4.3.1.
Escriba un servidor que reciba un número y responda el cuadrado de este
número.

4.3.2.
Escriba un servidor que pueda recibir un número y responda con un opera-
ción sobre este número. Este servidor puede recibir un mensaje que empiece por
“fun:”, si recibe este mensaje cambia la operación a las especificada. El servidor
debe responder las funciones seno, coseno y tangente. Por defecto debe empezar
calculando el coseno. Por ejemplo, si el primer número que recibe es 0, debe
responder 1, si después recibe π/2 debe responder 0, si luego recibe “fun:sin”
debe cambiar la operación actual a seno, es decir a a partir de ese momento
debe calcular senos. Si enseguida recibe 0 debe responder 0.

5
1 import [Link].*;
import [Link].*;
3
public class EchoClient {
5 public static void main(String[] args) throws IOException {

7 Socket echoSocket = null;


PrintWriter out = null;
9 BufferedReader in = null;

11 try {
echoSocket = new Socket("[Link]", 35000);
13 out = new PrintWriter([Link](), true);
in = new BufferedReader(new InputStreamReader(
15 [Link]()));
} catch (UnknownHostException e) {
17 [Link]("Don’t know about host!.");
[Link](1);
19 } catch (IOException e) {
[Link]("Couldn’t get I/O for "
21 + "the connection to: localhost.");
[Link](1);
23 }

25 BufferedReader stdIn = new BufferedReader(


new InputStreamReader([Link]));
27 String userInput;

29 while ((userInput = [Link]()) != null) {


[Link](userInput);
31 [Link]("echo: " + [Link]());
}
33
[Link]();
35 [Link]();
[Link]();
37 [Link]();
}
39 }

Figura 3: clase cliente que envı́a datos y recibe respuestas

6
1 import [Link].*;
import [Link].*;
3
public class EchoServer {
5 public static void main(String[] args) throws IOException {

7 ServerSocket serverSocket = null;


try {
9 serverSocket = new ServerSocket(35000);
} catch (IOException e) {
11 [Link]("Could not listen on port: 35000.");
[Link](1);
13 }

15 Socket clientSocket = null;


try {
17 clientSocket = [Link]();
} catch (IOException e) {
19 [Link]("Accept failed.");
[Link](1);
21 }

23 PrintWriter out = new PrintWriter([Link](), true);


BufferedReader in = new BufferedReader(
25 new InputStreamReader(
[Link]()));
27 String inputLine, outputLine;

29 while ((inputLine = [Link]()) != null) {


[Link](‘‘Mensaje:’’ + inputLine);
31 outputLine = ‘‘Respuesta’’ + inputLine ;
[Link](outputLine);
33 if ([Link]("Respuestas: Bye."))
break;
35 }
[Link]();
37 [Link]();
[Link]();
39 [Link]();
}
41 }

Figura 4: clase servidor que regresa el mismo mensaje que lee

7
4.4. Servidor web
El código 5 presenta un servidor web que atiende una solicitud. Implemente
el servidor e intente conectarse desde el browser.

4.5. Ejercicios
4.5.1.
Escriba un servidor web que soporte múltiples solicitudes seguidas (no con-
currentes). El servidor debe retornar todos los archivos solicitados, incluyendo
páginas html e imágenes.

5. Datagramas
Los programas escritos en las secciones anteriores presentan ejemplos de apli-
caciones que se conectan punto a punto con otras aplicaciones. Estos ejemplos
usaban por debajo el protocolo TCP.
Esta sección muestra programas que se comunican sin importar si los men-
sajes enviados fueron o no recibidos, o en que orden llegan. Esto, se implementa
usando el protocolo UDP. La abstracción fundamental para hacer este tipo de
programas es el datagrama y el [Link].

5.1. Datagramas
Un datagrama es un mensaje independiente autocontenido que es enviado a
través de la red, y cuya llegada, tiempo de llegada y contenido no son garanti-
zados.
Estos datagramas son útiles para implementar servicios cuyos mensajes no
tienen un contenido del cual dependen procesos fundamentales. Por ejemplo
usted quiere que la comunicación entre un avión y la torre de control sea inme-
diata y garantizada, sin embargo, si tiene una página que muestra el estado del
tiempo en la playa, no le importa si el último mensaje es de hace 1 hora y de
pronto no es tan exacto.
En esta sección vamos a construir un servidor que reporta la hora cuando
recibe un mensaje que le solicita este servicio. Igualmente construiremos un
cliente que pide el servicio.
La figura 6 implementa un servidor de datagramas. El servidor primero crea
un objeto de tipo Datagramsocket y lo asocia al puerto 45000. Después, en
le método startServer crea un buffer de 256 bytes que es usado para crear un
DatagramPacket con este tamaño. Una vez se tiene el paquete creado se le dice
que espere por un paquete,

DatagramPacket packet = new DatagramPacket(buf, [Link]);


[Link](packet);

8
1
import [Link].*;
3 import [Link].*;

5 public class HttpServer {

7 public static void main(String[] args) throws IOException {

9 ServerSocket serverSocket = null;


try {
11 serverSocket = new ServerSocket(35000);
} catch (IOException e) {
13 [Link]("Could not listen on port: 35000.");
[Link](1);
15 }

17 Socket clientSocket = null;


try {
19 [Link]("Listo para recibir ...");
clientSocket = [Link]();
21 } catch (IOException e) {
[Link]("Accept failed.");
23 [Link](1);
}
25
PrintWriter out = new PrintWriter([Link](), true);
27 BufferedReader in = new BufferedReader(
new InputStreamReader(
29 [Link]()));
String inputLine, outputLine;
31
while ((inputLine = [Link]()) != null) {
33 [Link]("Received: " + inputLine);
if (![Link]()) {
35 break;
}
37 }
outputLine = "<!DOCTYPE html>"
39 + "<html>"
+ "<head>"
41 + "<meta charset=\"UTF-8\">"
+ "<title>Title of the document</title>\n"
43 + "</head>"
+ "<body>"
45 + "My Web Site"
+ "</body>"
47 + "</html>" + inputLine;
[Link](outputLine);
49
[Link]();
51 [Link]();
[Link]();
53 [Link]();
}
55 }

Figura 5: clase que implementa un servidor web de un request

9
el servidor espera a recibir un mensaje, y una vez lo recibe, lee la información
de dirección ip y puerto de origen. Con esta información crea un paquete de
respuesta mensaje de respuesta y responde al cliente.
La figura 7 implementa un cliente de datagramas. Este cliente crea un socket
de datagramas pegado a un puerto, luego crea un paquete de salida y envı́a
el datagrama al cliente solicitado. Luego espera por la respuesta del servidor.
Observe que si no tiene respuesta el cliente se queda esperando para siempre. Si
necesita cancelar la espera, puede hacer un pool de hilos, colocar la actividad
en un hilo del pool, y asignarle un tiempo máximo de espera al pool de hilos.

5.2. Ejercicios
5.2.1.
Utilizando Datagramas escriba un programa que se conecte a un servidor
que responde la hora actual en el servidor. El programa debe actualizar la hora
cada 5 segundos según los datos del servidor. Si una hora no es recibida debe
mantener la hora que tenı́a. Para la prueba se apagará el servidor y después de
unos segundos se reactivará. El cliente debe seguir funcionando y actualizarse
cuando el servidor este nuevamente funcionando.

6. Invocación remota de métodos: RMI


El sistema RMI (Remote method invocation) permite a un programa co-
rriendo en un máquina virtual de Java llamar los métodos de objetos que están
corriendo en otra máquina virtual de Java. Es decir, RMI permite la comunica-
ción, utilizando un modelo orientado a objetos, entre dos aplicaciones Java.

6.1. Modelo general de comunicación


El modelo RMI busca implementar un modelo de objetos distribuidos con
una semántica clara, simple y cercana a la semántica de objetos propuesta en
el lenguaje de programación Java. Por esto utiliza las abstracciones de objeto
y método como eje fundamental del modelo. Ası́, en un aplicación distribuida
tı́pica el servidor crea uno o varios objetos que se hacen disponibles para atender
llamados remotos. Por su parte, el cliente localiza estos objetos, obtiene referen-
cias remotas a ellos y llama sus métodos. Para lograr esto la aplicación necesita
soportar los siguientes mecanismos:

Mecanismos de localización de objetos remotos: para hacer un llamado


remoto un cliente necesita saber la referencia remota de un objeto. Hay
muchos mecanismos para obtener esta referencia, por ejemplo podrı́a re-
cibir un e-mail, un mensaje de texto, o incluso recibirla por teléfono. El
mecanismo no es importante, lo importante es tener la referencia. Sin em-
bargo, RMI provee un servicio de nombres (rmiregistry) que permite que
el servidor publique sus objetos asociándolos con un nombre, y permita

10
import [Link];
2 import [Link];
import [Link];
4 import [Link];

6 import [Link];
import [Link];
8 import [Link];
import [Link];
10
public class DatagramTimeServer {
12
DatagramSocket socket;
14
public DatagramTimeServer() {
16 try {
socket = new DatagramSocket(4445);
18 } catch (SocketException ex) {
[Link]([Link]()).log([Link], null, ex);
20 }

22 }

24 public void startServer() {


byte[] buf = new byte[256];
26 try {

28 DatagramPacket packet = new DatagramPacket(buf, [Link]);


[Link](packet);
30
String dString = new Date().toString();
32 buf = [Link]();
InetAddress address = [Link]();
34 int port = [Link]();
packet = new DatagramPacket(buf, [Link], address, port);
36 [Link](packet);

38
} catch (IOException ex) {
40 [Link]([Link]()).log([Link], null, ex);
}
42 [Link]();
}
44
public static void main(String[] args){
46 DatagramTimeServer ds = new DatagramTimeServer();
[Link]();
48 }
}

Figura 6: clase que implementa un servidor de datagramas

11
1 import [Link];
import [Link];
3 import [Link];
import [Link];
5 import [Link];
import [Link];
7 import [Link];
import [Link];
9
public class DatagramTimeClient {
11
public static void main(String[] args) {
13 byte[] sendBuf = new byte[256];
try {
15 DatagramSocket socket = new DatagramSocket();
byte[] buf = new byte[256];
17 InetAddress address = [Link]("[Link]");

19 DatagramPacket packet = new DatagramPacket(buf, [Link], address, 4445);


[Link](packet);
21
packet = new DatagramPacket(buf, [Link]);
23 [Link](packet);
String received = new String([Link](), 0, [Link]());
25 [Link]("Date: " + received);
} catch (SocketException ex) {
27 [Link]([Link]()).log([Link], null, ex);
} catch (UnknownHostException ex) {
29 [Link]([Link]()).log([Link], null, ex);
} catch (IOException ex) {
31 [Link]([Link]()).log([Link], null, ex);
}
33 }
}

Figura 7: clase que implementa un cliente de datagramas

12
también que el cliente obtenga la referencia a un objeto remoto por me-
dio de dicho nombre. Otra forma de recibir referencias remotas es que
sean pasadas como parámetros o valores de retorno cuando se invoca un
método.
IMPORTANTE: Observe que el mecanismo de nombrado permite desaco-
plar las implementaciones del cliente y el servidor. Es decir, el cliente y
el servidor ya no tienen que conocerse, el cliente solo esta interesado que
alguien le suministre el servicio asociado a un nombre especı́fico.
Mecanismo de comunicación: Este mecanismo es el que me permite hacer
la comunicación remota. En la siguiente sección se presenta algún detalle
técnico de este mecanismo.

Mecanismo de carga de definiciones de clases que son pasadas como refe-


rencias o como valores de retorno: Este mecanismo de cargue dinámico de
bytecode es de vital importancia en el modelo RMI. Lo que permite es que
si el cliente o el servidor no tiene la definición de una clase especı́fica, la
pueden solicitar remotamente para que estas sea transferida. Por supuesto
para que esto pueda realizarse las definiciones de clases tienen que estar
disponibles en algún lugar conocido y accesible tanto para el cliente como
para el servidor

La figura 8 muestra un escenario de comunicación estándar, donde el cliente


usa el rmiregistry para localizar un objeto remoto, luego llama un método en
dicho objeto, el servidor descarga definiciones de clase si alguno de los paráme-
tros es de un tipo que el servidor no conoce, el servidor retorna un valor, y
finalmente si el cliente no conoce el tipo de retorno tiene la opción de descargar
la definición de clase.

6.2. Stubs y Skeletons


RMI utiliza un mecanismo basado en stubs y skeletons para implementar
la comunicación entre objetos remotos. El mecanismo tiene un funcionamiento
básico en el cual el cliente invoca un método en el stub (que es un objeto local),
y es este el encargado de hacer la invocación del método en el objeto remoto,
i.e., oculta la complejidad de la comunicación remota. Este stub también es
el encargado de serializar (preparar para transmitirlos) los parámetros que se
envı́an al objeto remoto. Igualmente el stub se encarga de recibir la respuesta
del llamado remoto y deserializarla para que pueda ser manejada por los objetos
[Link] función del skeleton es muy similar a la del stub pero del lado del
servidor. El skeleton espera por el llamado remoto, recibe los parámetros, realiza
el llamado al método necesario y retorna el valor que regresa el método.
Observe que, aunque el stub como el skeleton se encargan de las complejida-
des de la comunicación, ambos objetos son solo proxies que son utilizados por
el cliente y el servidor para llamar métodos reales sobre objetos locales.

13
rmiregistry

n1: refO1
n2: refO2
1: cliente localiza referencia remota
...

Servidor
2: cliente invoca métodos
cliente

3: servidor descarga clases

4: cliente descarga clases

Servidor web con definiciones


Servidor web con definiciones
de clase del cliente
de clase del servidor

Figura 8: Modelo de comunicación RMI

Aunque el conocer este funcionamiento es muy útil, usted verá que la plata-
forma RMI oculta al programador estos detalles de bajo nivel, y la programación
es totalmente transparente a este modelo.

6.3. Ejemplo
Vamos a implementar un servidor echo que retorna el mismo mensaje que
recibe, pero con la etiqueta adicional “desde el servidor: ”. Veamos primero la
implementación del servidor.

6.3.1. Implementación del servidor


Primero tengo que declarar un interfaz remota, esta interfaz describe los ser-
vicios que prestará el objeto remoto. solo los métodos que se declaran en estas
interfaces son los que pueden ser llamados remotamente. Es decir, esta interface
define el contrato de servicios remotos que presta un objeto. La interface extien-
de la interface Remote que es una interface de marcación, es decir que no define
métodos, y que solo indica que será una interface de métodos que se pueden lla-
mar remotamente. La única condición de los métodos definidos en una interface
de tipo Remote es que deben lanzar la excepción RemoteException. La figura 9
muestra el código de la interface EchoServer que extiende la interface Remote.
La interface define un método echo que recibe un String como parámetro y
retorna un objeto de tipo String como respuesta.
Ahora que ya definimos los métodos que se pueden llamar remotamente
debemos definir una clase que implemente estos métodos. La figura 10 muestra
el código de la clase EchoServerImpl que implementa la interface EchoServer

14
1 package rmiexample;

3 import [Link];
import [Link];
5
public interface EchoServer extends Remote {
7 public String echo(String cadena) throws RemoteException;

9 }

Figura 9: Interface que extiende la interface Remote

definida anteriormente. Esta clase implementa el método echo y adicionalmente


define un constructor que realiza la publicación del objeto remoto en el servicio
de referenciación por nombres (rmiregistry) correspondiente.

6.3.2. Implementación del cliente


El último paso en la implementación es escribir el cliente que se conectará
utilizando RMI. La figura 11 muestra el código de la clase que implementa el
cliente RMI. Esta clase primero carga un administrador de seguridad, luego
se conecta al rmiregistry para solicitar la ubicación de un servicio utilizando el
nombre, y finalmente invoca el método sobre el objeto remoto. Estudie el código
y revise la documentación de las clases y métodos utilizados.

6.3.3. ¿Cómo ejecutar el software?


La ejecución de los programas RMI es un poco complicada porque hay que
tener en cuenta las consideraciones de seguridad y de arquitectura de la aplica-
ción. Para ejecutarla considere estos dos aspectos primero:
Class Path. El class path es el conjunto de directorios donde se encuan-
tran las clases que necesita su programa. Al invocar la máquina virtual de
Java se puede pasar un parámetro indicándole dónde buscar las clases. Es-
te parámetro se le indica a la máquina virtual usando “-cp” y adicionando
en seguida los directorios del class path, donde la máquina virtual buscará
las classes de su programa. Adicionalmente, al ejecutar varios de los com-
ponentes de este taller debe tener en cuenta ejecutarlos desde la raı́z del
class path, en particular el registry (servicio de directorio que relaciona
nombres con referencias de objetos).
Seguridad. También necesita archivos policy de seguridad que determi-
nan que acceso tienen los programas que se conectan. Este archivo se
puede crear en una carpeta separada de las clases. Para la ejecución de
este ejemplo utilizaremos un archivo de seguridad con le nombre policy, el
contenido de este archivo debe ser:

grant {
permission [Link];

15
1 package rmiexample;

3 import [Link];
import [Link];
5 import [Link];
import [Link];
7
public class EchoServerImpl implements EchoServer{
9
public EchoServerImpl(String ipRMIregistry,
11 int puertoRMIregistry, String nombreDePublicacion){
if ([Link]() == null) {
13 [Link](new SecurityManager());
}
15 try {
EchoServer echoServer =
17 (EchoServer) [Link](this,0);
Registry registry = [Link](ipRMIregistry, puertoRMIregistry);
19 [Link](nombreDePublicacion, echoServer);
[Link]("Echo server ready...");
21 } catch (Exception e) {
[Link]("Echo server exception:");
23 [Link]();
}
25 }

27 public String echo(String cadena) throws RemoteException {


return "desde el servidor: " + cadena;
29 }

31 public static void main(String[] args){


EchoServerImpl ec = new EchoServerImpl("[Link]", 23000, "echoServer");
33 }
}

Figura 10: Clase que implementa la interface EchoServer

16
package rmiexample;
2
import [Link];
4 import [Link];

6 /**
*
8 * @author dnielben
*/
10 public class EchoClient {

12 public void ejecutaServicio(String ipRmiregistry, int puertoRmiRegistry,


String nombreServicio) {
14 if ([Link]() == null) {
[Link](new SecurityManager());
16 }
try {
18 Registry registry = [Link](ipRmiregistry, puertoRmiRegistry);
EchoServer echoServer = (EchoServer) [Link](nombreServicio);
20 [Link]([Link]("Hola como estas?"));
} catch (Exception e) {
22 [Link]("Hay un problema:");
[Link]();
24 }
}
26
public static void main(String[] args){
28 EchoClient ec = new EchoClient();
[Link]("[Link]", 23000, "echoServer");
30 }
}

Figura 11: Clase que implementa el cliente que se conecta utilizando RMI

17
permission [Link] "*:1024-", "connect,accept";
};

Este archivo le da permisos a la máquina virtual para conectarse y aceptar


conexiones en todos los puertos mayores a 1024. Una vez tenga los archivos de
seguridad ya podrá ejecutar la aplicación.
Lo primero es iniciar el servidor de nombres donde se registrarán los objetos
que prestan servicios remotos, este servicio se iniciará en le puerto 23000 y los
debe ejecutar desde la raiz del classpath (es decir desde el directorio donde el
registry puede encontrar las definiciones de clase):

rmiregistry 23000

Ahora para ejecutar el servidor debe ejecutar desde la consola el siguiente


comando:

java -cp .
-[Link]=file:/<pathToClasses>/
-[Link]=file:/<pathToPolicy>/policy
[Link]

Este comando invoca la máquina virtual de java con tres parámetros especı́fi-
cos. El primer parámetro define un classpath (cp) donde el programa busca las
definiciones de clase. También define el codebase que es donde el sistema de
RMI busca las definiciones de clases que necesita enviar por la red. Finalmente,
antes de invocar la clase a ejecutar, define la ubicación del archivo de seguridad.
De manera similar para ejecutar el cliente debe ejecutar desde la consola el
siguiente comando:

java -cp .
-[Link]=file:/<pathToClasses>/
-[Link]=file:/<pathToPolicy>/policy
[Link]

6.4. Ejercicios
6.4.1.
CHAT: Utilizando RMI, escriba un aplicativo que pueda conectarse a otro
aplicativo del mismo tipo en un servidor remoto para comenzar un chat. El
aplicativo debe solicitar una dirección IP y un puerto antes de conectarse con el
cliente que se desea. Igualmente, debe solicitar un puerto antes de iniciar para
que publique el objeto que recibe los llamados remotos en dicho puerto.

18

También podría gustarte