Documentos de Académico
Documentos de Profesional
Documentos de Cultura
1
1. Introducción a las redes
1.1. Concepto
Las redes interconectan computadoras con distintos sistemas operativos, ya sea dentro de una
empresa u organización (LANs) o por todo el mundo (WANs, Internet).
Las razones más usuales para decidir la instalación de una red son:
En las redes basadas en estructuras cliente-servidor, los servidores ponen a disposición de sus
clientes recursos, servicios y aplicaciones.
Dependiendo de qué recursos ofrece el servidor y cuáles se mantienen en los clientes se pueden
hacer distinciones entre distintas estructuras cliente-servidor.
2
A continuación, se presentarán brevemente los distintos conceptos.
En esta red se dispone al menos de dos servidores distintos. Uno de ellos actúa
meramente como servidor de base de datos y el resto como servidor de aplicaciones. Los
servidores de aplicaciones de esta red también son los responsables de acceso a las bases
de datos. En las estaciones de trabajo funcionan los clientes de los programas de
aplicación correspondientes.
Las bases de datos están repartidas en distintos servidores o incluso clientes. Las
aplicaciones funcionan igualmente en distintos servidores o en parte también en clientes.
A este sistema se le conoce como Aplicaciones Distribuidas.
3
Para ellos se utilizan cuatro elementos fundamentales: servidores de archivos, estaciones de
trabajo, tarjetas de red y cables.
A ellos se les suman los elementos propios de cada cableado, así como los manuales y el
software de red, a efectos de la instalación y mantenimiento.
Los cables son generalmente de tres tipos: UTP par trenzado, coaxial y fibra óptica.
La manera en que están conectadas las computadoras no es arbitraria, sino que siguen estándares
físicos llamados topologías.
En este sistema una sola computadora por vez puede mandar datos los cuales son
escuchados por todas las computadoras que integran el bus, pero solo el receptor designado
los utiliza.
Ventajas:
• Es la más barata.
• Apta para oficinas medianas y chicas.
Desventajas:
4
2. TOPOLOGÍA ESTRELLA
En este esquema todas las estaciones están conectadas a un concentrador (Hub o Switche),
actualmente se utiliza un Switche, con cable por red o inalámbrico.
Para futuras ampliaciones pueden colocarse otros Switches en cascada dando lugar a la
estrella jerárquica.
Ventajas:
Desventajas:
Es un desarrollo de IBM que consiste en conectar cada estación con otras dos formando un
anillo.
Los servidores pueden estar en cualquier lugar del anillo y la información es pasada en un
único sentido de una a otra estación hasta que alcanza su destino.
Por ejemplo, en esta topología envía una señal por toda la red, si la terminal quiere
transmitir pide el TOKEN y hasta que lo tiene puede transmitir.
5
Si no está la señal la pasa a la siguiente en el anillo y sigue circulando hasta que alguna
terminal pide permiso para transmitir.
Ventajas:
• No existen colisiones, pues cada paquete tiene una cabecera o TOKEN que identifica al
destino.
Desventajas:
Por último, actualmente no hay conexiones físicas entre estaciones, sino que existen
centrales de cableado o MAU que implementa la lógica de anillo sin que estén conectadas
entre sí; evitando las caídas.
4. TOPOLOGÍA ÁRBOL
En esta topología que es una generalización del tipo bus, el árbol tiene su primer nodo en la raíz
y se expande hacia afuera utilizando ramas, en donde se conectan las demás terminales.
Esta topología permite que la red se expanda y al mismo tiempo asegura que nada más existe una
ruta de datos entre dos terminales cualesquiera.
Las desventajas son las mismas de la topología lineal o bus, para cada rama, y la ventaja es de la
expandir redes de bus ya existentes.
6
5. TOPOLOGÍA MESH.
Es una combinación de más de una topología, como podría ser un bus combinado con una
estrella.
Este tipo de topología es común en lugares en donde tenían una red bus y luego la fueron
expandiendo en estrella.
Son complicadas para detectar su conexión por parte del servicio técnico para su reparación.
1.4. Concentradores
Son equipos que permiten estructurar el cableado de las redes, la variedad de tipos y
características de estos equipos es muy grande. Cada vez disponen de mayor número de
capacidades como aislamiento de tramos de red, capacidad de conmutación de las salidas para
aumentar la capacidad de la red, gestión remonta, etc.; por lo que se tiende a incorporar más
funciones en el concentrador.
7
En la actualidad, la tarea de los concentradores la realizan, con frecuencia, los
conmutadores (switches).
En las topologías anteriores se comparte el medio, por parte de más de una PC, con lo que puede
ocurrir que 2 o más PC intenten acceder al medio al mismo tiempo produciéndose una colisión
que provocaría errores en los datos enviados a través de medio.
Para evitar estas situaciones o corregirlas se dispone de varios mecanismos de acceso al medio
de forma controlada que se basan en la secuencia de bits que habilita el permiso para transmitir
por el medio físico.
1. Si existe una estación de trabajo "jefe" que centralice el paso de la señal, los métodos se
llaman:
o POLLING. Si la topología usada es bus.
o LUP CENTRAL. Si la topología usada es de tipo anillo.
2. Si no existe esa estación jefe que controle el paso de la señal o TESTIGO, tenemos los
métodos:
o PASO DEL TESTIGO EN ANILLO. Usa la topología en anillo.
o TESTIGO EN BUS. Usa la topología en bus.
3. Si no utilizamos ningún método de control sobre el medio para habilitar permisos de
transmisión de las estaciones tenemos:
o TÉCNICAS DE ACCESO SORDAS: se transmiten sin consultar el medio
previamente, para ver si está libre.
o TÉCNICAS CON ESCUCHAS DEL MEDIO. Dan lugar a un control del tipo
aleatorio.
✓ PARA TOPOLOGÍA BUS. Esta técnica se conoce como CSMA/CD
técnica de acceso al medio con escuchas y detección de colisiones.
✓ PARA TOPOLOGÍA ANILLO. Esta técnica se la conoce como
INSERCIÓN DE REGISTROS.
Las redes de área local (LAN por las siglas de Local Area Network) son las de uso más
frecuente. Son conjuntos de máquinas interconectadas, ubicadas en extensiones
relativamente pequeñas. Desde nuestros hogares hasta grandes edificios de oficinas, pasando
por entidades gubernamentales e instituciones académicas. Es decir, son redes de propiedad
privada dentro de un solo edificio de hasta unos cuantos kilómetros de extensión.
Este tipo de redes son las más comunes. En todos los lugares de trabajo del mundo, con
más de una computadora interconectada, existe seguramente una LAN activa.
Las LAN permiten la interacción entre múltiples equipos para compartir datos y recursos.
Muchas computadoras accediendo a la misma impresora, al mismo servidor, a la misma
conexión a Internet. Todas ellas compartiendo datos a gran velocidad.
En las redes de área local la distancia entre una máquina y otra no suele ser muy grande. Por
debajo de los 100 metros es lo normal. Sin embargo, con configuraciones especiales, pueden
existir redes LAN con computadoras a 5 km de distancia entre sí.
Por otro lado, la velocidad de transmisión de datos en este tipo de redes es muy alta. El
protocolo de interconexión más común es Ethernet. Por cable entrelazado puede llegar a los
100 Mbps. Por fibra óptica podría alcanzar los 1000 Mbps.
Teóricamente no existe un límite de computadoras que se puedan conectar a una LAN. Sin
embargo, con el uso de muy buenos equipos y excelente organización de la red, a partir de
los 400 ó 500 equipos se percibe degradación en el rendimiento de la red.
Las LAN se distinguen de otro tipo de redes por las siguientes tres características: tamaño,
tecnología de transmisión y topología:
9
• Las LAN están restringidas en tamaño. Las computadoras se distribuyen dentro de la
LAN para obtener mayor velocidad en las comunicaciones dentro de un edificio o un
conjunto de edificios, lo cual significa que el tiempo de transmisión del peor caso está
limitado y se conoce de antemano.
Conocer este límite hace posible usar ciertos tipos de diseños que de otra manera no
serían prácticos y también simplifica la administración de la red.
• Las LAN a menudo usan una tecnología de transmisión. Que consiste en un cable sencillo
al cual están conectadas todas las máquinas.
Las LAN tradicionales operan a velocidades de 10 a 100 Mbps, Las más nuevas pueden
operar a velocidades muy altas, de hasta cientos de megabits/seg.
Básicamente existen tres topologías de red: estrella (Star), canal (Bus) y anillo (Ring).
Pero actualmente se ha divulgado la topología estrella.
Una LAN con sus nodos interconectados con tecnología WiFi se conoce como red
inalámbrica de área local.
Con una WLAN no hay que tender engorrosos cables en la oficina para lograr la
interconexión. Esta se realiza mediante ondas de radio de alta frecuencia. Una desventaja es
que estas redes son menos seguras que sus versiones conectadas físicamente. La señal
podría ser interceptada y desencriptada por personas indeseadas.
Para evitar problemas de rendimiento pueden interconectarse varias LAN entre sí, sin
importar la distancia. Si estas redes están muy separadas unas de otras, pasan a llamarse
redes de área metropolitana o MAN. Y aún más, si la distribución abarca zonas geográficas
todavía mayores se les conoce como redes de área amplia o WAN.
10
2. MAN (Redes de Área Metropolitana)
Una red de área metropolitana (MAN por las siglas en inglés de Metropolitan Area
Network) consiste en computadoras compartiendo recursos entre sí en áreas de cobertura de
mayor tamaño que una LAN, pero menor que una WAN. Funcionan de forma muy
parecida a una red de área local, pero cumplen estándares tecnológicos diferentes. Estas
mejoras son necesarias para subsanar los problemas de latencia (retardo en la entrega de
información) y pérdida de calidad de la señal en interconexiones que abarcan largas
distancias.
Una MAN podría abarcar una serie de oficinas cercanas o en una ciudad, puede ser pública o
privada.
La principal razón para distinguir las MAN como una categoría especial es que se ha
adoptado un estándar para ellas, y este se llama DQDB (Distributed-queue dual-bus - Bus
dual de cola distribuida).
Se apoya en las transferencias de datos con estado sin conexión, en las transferencias de
datos orientadas a conexión, y en comunicaciones isócronas tales como la comunicación por
voz. Un ejemplo de red que proporciona métodos de acceso DQDB es la que sigue el
estándar IEEE 802.6.
Generalmente usan un bus doble, ida y vuelta, con fibra óptica, para interconectar las
diferentes LAN a la red. También se consiguen redes MAN usando pares de cobre o
microondas. Por la mayor estabilidad y menor latencia que ofrecen, son ideales para
ofrecer servicios multimedia y videovigilancia en grandes ciudades, entre otras ventajas.
Es decir, una MAN puede manejar datos y voz, e incluso podría estar relacionada con una
red de televisión por cable local.
11
Como el resto de las redes cableadas, tiene su versión inalámbrica llamada WMAN
(Wireless Metropolitan Area Network). Esta red utiliza tecnologías de telefonía celular
como LTE y WiMax para interconectar sus miembros.
Velocidad de transmisión: Las redes MAN bucle ofrecen velocidades de 10 Mbps, 20 Mbps, 16
gbps y 10 gbps mediante fibra óptica.
Las redes de área amplia (WAN por las siglas de Wide Area Network), son redes
informáticas LAN y MAN interconectadas entre sí. Sus nodos están separados por
distancias que pueden abarcar continentes enteros. Los integrantes de esas redes no
necesariamente están conectados físicamente. Hacen uso de servicios de cables
submarinos, microondas y satelitales para integrar sus diferentes nodos.
Son muy usadas por grandes empresas que abarcan mucho territorio. Generalmente
necesitan usar redes privadas virtuales (VPN) para conseguir la privacidad necesaria en el
intercambio de datos. Otro uso muy frecuente es para ofrecer conexión web a clientes de
grandes proveedores de Internet (ISP – Internet Service Provider).
Su versión inalámbrica es una WWAN. Esta interconecta al resto de los nodos mediante el
uso de redes de telefonía celular con tecnología LTE, WiMax, GSM, CDMA2000, UMTS,
entre otras.
12
WAN contiene una colección de máquinas dedicadas a ejecutar programas de usuario
(aplicaciones), estas máquinas se llaman Hosts.
Los Hosts están conectados por una subred de comunicación. El trabajo de una subred es
conducir mensajes de un Host a otro.
La separación entre los aspectos exclusivamente de comunicación de la red (la subred) y los
aspectos de aplicación (Hosts), simplifica enormemente el diseño total de la red.
En muchas redes de área amplia, la subred tiene dos componentes distintos: las líneas de
transmisión y los elementos de conmutación.
• Las líneas de transmisión (también llamadas circuitos o canales) mueven los bits de una
máquina a otra.
• Los elementos de conmutación son computadoras especializadas que conectan dos o más
líneas de transmisión. Por ejemplo, los Routers.
Cuando los datos llegan por una línea de entrada, el elemento de conmutación debe escoger
una línea de salida para enviarlos.
Como término genérico para las computadoras de conmutación, les llamaremos enrutadores
(routers).
La velocidad de transmisión se encuentra entre 1 Mbps y 1 Gbps, aunque este último límite
puede cambiar drásticamente con los avances tecnológicos.
• PAN (Personal Area Network): Se denomina red de área personal la que abarca los
diferentes dispositivos de uso cercano de un usuario. Teléfono celular, laptop, cámaras
13
de fotos, tabletas, etc, son los más comunes. Permite el intercambio de archivos de
manera sencilla entre los aparatos. Su versión inalámbrica hace uso de la red WiFi, el
Bluetooth o los rayos infrarrojos para intercambiar información.
• VLAN (Virtual Local Area Network): Funciona como una VPN dentro de una red
local. Permite la creación de una conexión privada entre dos o más nodos dentro del
universo de una LAN. Ideal, por ejemplo, para separar el acceso a la red de diferentes
departamentos de una empresa. Son creadas vía software, por lo que sus nodos no
necesitan estar interconectados directamente entre sí.
• SAN (Storage Area Network): Las redes de área de almacenamiento (SAN) son una
tecnología usada para enlazar unidades de almacenamiento (básicamente discos
duros) a una red local, de manera de compartir su uso en todas las áreas de una
empresa. Este sistema puede crecer casi ilimitadamente sin afectar el rendimiento de la
red ya que el tráfico de almacenamiento se mantiene separado del tráfico de los usuarios.
Ethernet es una tecnología desarrollada para las redes LAN que permite transmitir información
entre computadoras a velocidades de 10 y 100 millones de bits por segundo (100 Mbps).
Si bien Ethernet es el sistema más popular, existen otras tecnologías como Token Ring, 100 VG.
Se usa en redes que no superan las 30 máquinas, de exceder este número conviene usar Token
Ring.
1. Un medio físico utilizado para transportar señales entre dos computadoras (adaptadores
de red y cableado).
2. Un juego de reglas o normas de acceso al medio (al cable, por ejemplo) que le permita a
las computadoras poder arbitrar o regular el acceso al sistema Ethernet (recordar que el
medio está compartido por todas las computadoras integrantes de la red).
3. Un estándar o patrón llamado trama o frame que consiste en un juego determinado de
bits, usados para transportar datos a través del sistema.
Cada computadora equipada con Ethernet opera en forma independiente de las otras estaciones
de la red, es decir que no hay una controladora central.
Todas las estaciones conectadas vía Ethernet se conectan a un sistema compartido de señales,
llamado medio.
Las señales Ethernet se transmiten en serie, un bit por vez, a través del canal Ethernet (llamado
de señal compartida) a cada una de las estaciones integrantes de la red Ethernet.
• El preámbulo: es una serie de unos y ceros, que serán utilizados por la computadora
destino (receptor) para conseguir la sincronización de la transmisión.
• Separador de la trama: son dos bits consecutivos utilizados para lograr alineación de
los bytes de datos. Son dos bits que no pertenecen a los datos, simplemente están a modo
de separador entre el preámbulo y el resto del paquete.
• Dirección de destino: es la dirección de la computadora a la que se le envía el paquete.
La dirección de difusión o broadcast (se le envía a todos los equipos) está compuesta por
uno solamente (son todos unos).
• Dirección de origen: es la dirección de la computadora que envía los datos.
• Longitud o tipo de datos: es el número de bytes de datos o el tipo de los mismos. Los
códigos de tipos de datos son mayores que 1500, ya que 1500 bytes es la máxima
longitud de los datos en Ethernet. Entonces, si este campo es menor que 1500 se estará
refiriendo a la longitud de los datos y si es mayor, se referirá al tipo de datos. El tipo de
datos tendrá un código distinto, por ejemplo para Ethernet que para Fast Ethernet.
• Datos: su longitud mínima es de 46 bytes y su largo máximo de 1500 bytes como dijimos
en el ítem anterior.
• Secuencia de chequeo de la trama: se trata de un chequeo de errores (CRC) que utiliza
32 bits. Este campo se genera generalmente por el hardware (placa de red).
Basándose en lo visto, sin contar preámbulo, separadores y CRC, la longitud de los paquetes
Ethernet serán:
La red Token-Ring es una implementación del standard IEEE 802.5, en el cual se distingue más
por su método de transmitir la información que por la forma en que se conectan las
computadoras.
Cuando una computadora desea mandar información debe de esperar a que le llegue el Token
vacío, cuando le llega utiliza el Token para mandar la información a otra computadora, entonces
cuando la otra computadora recibe la información regresa el Token a la computadora que envió
con el mensaje de que fue recibida la información.
Así se libera el Token para volver a ser usado por cualquiera otra computadora.
15
Aquí debido a que una computadora requiere el Token para enviar información no hay
colisiones, el problema reside en el tiempo que debe esperar una computadora para obtener el
Token sin utilizar.
Todas las estaciones se deben de configurar con la misma velocidad para que funcione la red.
En redes grandes con tráfico de datos pesado el Token Ring es más eficiente que Ethernet.
"Por lo tanto es conveniente usar Token ring en redes que superan las 30 máquinas."
A continuación, trataremos los componentes más importantes de una instalación física de redes a
saber:
1. Adaptadores de red:
Si bien hasta ahora hablamos de las topologías o formas de conexión de computadoras entre sí
por intermedio de cables, todavía no se dijo nada sobre los tipos de cables existentes y sobre
cómo se conectan los cables a las computadoras.
Una tarjeta de red no es más que una placa o adaptador físico de red que permite establecer la
comunicación entre diversas computadoras de la red.
16
2. Medios físicos de conexión (medios de transmisión y conectores):
Los elementos físicos para la conexión para cable COAXIAL son los siguientes conectores:
17
Otros elementos físicos para la conexión para cable UTP son los siguientes:
Hub
Switche
Si bien la palabra estructurado no es común que figure en los diccionarios que no sean técnicos,
sabemos que proviene de estructura.
Si traducimos esta definición al área que nos respecta, podemos empezar diciendo que el
cableado estructurado deberá respetar a ciertas normas de distribución, no solo de los cables en
sí, sino también de todos los dispositivos involucrados, como ser los conectores de lo que
hablamos anteriormente.
Cuando nos referimos a distribución, hablamos de la disposición física de los cables y los demás
accesorios.
Para dar un ejemplo práctico, no podemos llamar cableado estructurado a un cableado UTP de la
instalación de la red, en el cual los cables estén tendidos de cualquier manera.
Al habla de orden, hablamos por un lado de la prolijidad de una instalación, pero también
estamos diciendo que las instalaciones no podrán llevarse a cabo como se les ocurra a los
instaladores, sino que deberán cumplir ciertas normas técnicas, como la norma EIA/TIA 586 A.
18
Otra de las características del Cableado Estructurado es que debe brindar flexibilidad de
conexión; esto significa que no tendremos que cambiar todo el cableado o hacer complejas
extensiones, cuando necesitemos agregar una computadora a la res o mudar un equipo de una
oficina a otra.
Si una empresa necesita realizar el cableado para la red (para datos) y para telefonía va a
optar por una solución que le ofrezca un cableado unificado, que sirva para ambos
servicios.
• Otra ventaja adicional está dada por la flexibilidad del cableado estructurado, que
veremos con un ejemplo: si por una reconfiguración de la oficina, necesitamos conectar
un teléfono donde había un puesto de computación, podremos hacerlo mediante una
operación sencilla, sin tener que instalar nuevos cables, no agujerear paredes.
Los pasos a principales que debería seguir un instalador son los siguientes:
Un buen instalador debe consultar con el administrador de la red o con el servicio que mantiene
el hardware de la empresa, si el equipamiento que poseen va a servir para ser conectado al
cableado a realizar.
Es decir que debemos relevar que elementos posee la empresa y ver cuáles sirven y cuales no
para que podamos utilizar los elementos seleccionados en la instalación de la red.
19
Consiste en varias tareas en donde la complejidad dependerá del edificio en que se va a instalar
la red.
Estas tareas involucran la medición de las distancias de los distintos ambientes, la cantidad de
agujeros que se deben realizar en las paredes, el tipo de pared con las que nos encontraremos, es
decir si se pueden agujerearse con facilidad o no), la determinacion de por dónde y cómo van a
pasar los cables y además es ideal poseer un plano de la planta para poder guiarse mejor y armar
sobre el mismo el mapa de la instalación.
A continuación, podemos ver un mapa de la planta que nos será de gran utilidad
Es común que, por errores en el relevamiento previo, nos demos cuenta que faltan materiales y
haya que salir corriendo de "apuro" a conseguirlos en algún proveedor cercano a la obra.
En el siguiente esquema vemos los pasos primordiales para poder armar un presupuesto de
cableado sin pasar sorpresas inesperadas.
La colocación de alojamientos para los cables ya sean, canaletas, zócalos, caños, bandejas, etc.
20
Una vez fijados los alojamientos para sostener los cables, se procede al tendido de los cables
sobre los mismos.
Y por último la colocación en las paredes los conectores (Plugs y Jaks RJ45) y san la
terminación final del trabajo como veremos en la siguiente figura:
En general la prueba del cableado se realiza, en general, fuera del horario de trabajo de la
empresa y consiste en la conexión final de los equipos y la prueba de acceso de los mismos a los
recursos de la red y la velocidad de transmisión.
1. Cable UTP.
2. Jack RJ45.
3. Plug RJ45.
4. Elementos para el alojamiento de cables (canaletas de cable, bandejas, caños, zócalos).
5. Rosetas.
6. Racks.
7. Patch Panels (patchetas).
8. Patch Cords.
21
2. Cliente (informática)
El cliente es una aplicación informática que se utiliza para acceder a los servicios que ofrece un
servidor, normalmente a través de una red de telecomunicaciones.
El término se usó inicialmente para los llamados terminales tontos, dispositivos que no eran
capaces de ejecutar programas por sí mismos, pero podían conectarse a un ordenador central y
dejar que éste realizase todas las operaciones requeridas, mostrando luego los resultados al
usuario. Se utilizaban sobre todo porque su costo en esos momentos era mucho menor que el de
un ordenador.
Muchas redes utilizan un terminal tonto en lugar de puestos de trabajo para la entrada de datos.
En estos sólo se exhiben datos o se introducen. Este tipo de terminales, trabajan contra un
servidor, que es quien realmente procesa los datos y envía pantallas de datos a los terminales.
Actualmente se suelen utilizar para referirse a programas que requieren específicamente una
conexión a otro programa, al que se denomina servidor y que suele estar en otra máquina. Ya no
se utilizan por criterios de coste, sino para obtener datos externos (por ejemplo páginas web,
información bursatil o bases de datos), interactuar con otros usuarios a través de un gestor central
(como por ejemplo los protocolos bittorrent o IRC), compartir información con otros usuarios
(servidores de archivos y otras aplicaciones Groupware) o utilizar recursos de los que no se
dispone en la máquina local (por ejemplo impresión)
Uno de los clientes más utilizados, sobre todo por su versatilidad, es el navegador web. Muchos
servidores son capaces de ofrecer sus servicios a través de un navegador web en lugar de requerir
la instalación de un programa específico.
Existen varios tipos de clientes, dependiendo de la cantidad de tareas que realice el cliente en
comparación con el servidor.
Almacenamiento Proceso de
Tipo de Cliente
de datos local datos local
Cliente pesado Sí Sí
Cliente híbrido No Sí
Cliente liviano No No
1. Cliente pesado
Un cliente pesado tiene capacidad de almacenar los datos y procesarlos, pero sigue necesitando
las capacidades del servidor para una parte importante de sus funciones. Un cliente de correo
electrónico suele ser un cliente pesado. Puede almacenar los mensajes de correo electrónico del
usuario, trabajar con ellos y redactar nuevos mensajes, pero sigue necesitando una conexión al
servidor para enviar y recibir los mensajes.
22
2. Cliente híbrido
Un cliente híbrido no tiene almacenados los datos con los que trabaja, pero sí es capaz de
procesar datos que le envía el servidor. Muchos programas de colaboración almacenan
remotamente los datos para que todos los usuarios trabajen con la misma información, y utilizan
clientes híbridos para acceder a esa información.
3. Cliente liviano
Un cliente liviano no tiene capacidad de procesamiento y su única función es recoger los datos
del usuario, dárselos al servidor, y mostrar su respuesta. Los primeros navegadores web eran
clientes livianos, simplemente mostraban las páginas web que solicitaba el usuario. Actualmente,
el uso de lenguajes de script, programas Java y otras funciones de DHTML dan una capacidad de
procesamiento a los navegadores, por lo que se consideran clientes Híbridos.
23
3. Servidor
En informática, un servidor es una computadora que, formando parte de una red, provee
servicios a otros denominados clientes.
• Una aplicación informática o programa que realiza algunas tareas en beneficio de otras
aplicaciones llamadas clientes. Algunos servicios habituales son los servicios de
archivos, que permiten a los usuarios almacenar y acceder a los archivos de una
computadora y los servicios de aplicaciones, que realizan tareas en beneficio directo del
usuario final. Este es el significado original del término. Es posible que un ordenador
cumpla simultáneamente las funciones de cliente y de servidor.
• Una computadora en la que se ejecuta un programa que realiza alguna tarea en beneficio
de otras aplicaciones llamadas clientes, tanto si se trata de un ordenador central
(mainframe), un miniordenador, un ordenador personal, una PDA o un sistema integrado;
sin embargo, hay computadoras destinadas únicamente a proveer los servicios de estos
programas: estos son los servidores por antonomasia.
A lo cual podemos llegar a la conclusión de que un servidor también puede ser un proceso que
entrega información o sirve a otro proceso. El modelo Cliente-servidor no necesariamente
implica tener dos ordenadores, ya que un proceso cliente puede solicitar algo como una
impresión a un proceso servidor en un mismo ordenador.
24
3.1. Tipos de servidores
• Servidor de archivo: almacena varios tipos de archivos y los distribuye a otros clientes
en la red.
• Servidor de fax: almacena, envía, recibe, enruta y realiza otras funciones necesarias para
la transmisión, la recepción y la distribución apropiada del fax.
• Servidor proxy: realiza un cierto tipo de funciones a nombre de otros clientes en la red
para aumentar el funcionamiento de ciertas operaciones (p. ej., prefetching y depositar
documentos u otros datos que se soliciten muy frecuentemente), también sirve seguridad,
esto es, tiene un Firewall. Permite administrar el acceso a internet en una Red de
computadoras permitiendo o negando el acceso a diferentes sitios Web.
• Servidor del acceso remoto (RAS): controla las líneas de módem de los monitores u
otros canales de comunicación de la red para que las peticiones conecten con la red de
una posición remota, responden llamadas telefónicas entrantes o reconocen la petición de
la red y realizan los chequeos necesarios de seguridad y otros procedimientos necesarios
para registrar a un usuario en la red.
• Servidor de uso: realiza la parte lógica de la informática o del negocio de un uso del
cliente, aceptando las instrucciones para que se realicen las operaciones de un sitio de
trabajo y sirviendo los resultados a su vez al sitio de trabajo, mientras que el sitio de
trabajo realiza el interfaz operador o la porción del GUI del proceso (es decir, la lógica de
la presentación) que se requiere para trabajar correctamente.
25
• Servidor de Base de Datos: (database server) provee servicios de base de datos a otros
programas u otras computadoras, como es definido por el modelo cliente-servidor.
También puede hacer referencia a aquellas computadoras (servidores) dedicadas a
ejecutar esos programas, prestando el servicio.
26
4. Comunicaciones en Red
4.1. Introducción
A continuación, se presenta una amplia introducción al tema de las comunicaciones TCP/IP, que
son la base del modelo sobre el que tiene sus fundamentos de Internet.
Las redes actuales utilizan para la transferencia de datos un concepto conocido como packet
switching. Los datos son encapsulados en paquetes que son transferidos desde el origen hasta el
destino, en donde los datos se van extrayendo de uno o más paquetes para reconstruir el mensaje
original.
En una red se trata de pasar la información de una máquina a otra, o viceversa; decidiendo cada
máquina qué es lo que quiere hacer con la información que le llega. Una de las principales
características de Java, es precisamente su tratamiento de la red, donde Java abstrae todos los
detalles de manejo a bajo nivel de la red, dejándole ese trabajo a la Máquina Virtual Java.
Protocolo de Comunicaciones
Para que dos o más ordenadores puedan conectarse a través de una red y ser capaces de
intercambiar datos de una forma ordenada, deben seguir un protocolo de comunicaciones que sea
aceptado por todos ellos.
27
El protocolo define las reglas que se deben seguir en la comunicación. Hay muchos protocolos
disponibles para ser utilizados; por ejemplo, el protocolo HTTP define como se van a comunicar
los servidores y navegadores Web y el protocolo SMTP define la forma de transferencia del
correo electrónico. Estos protocolos, son protocolos de aplicación que actúan al nivel de
superficie, pero también hay otros protocolos de bajo nivel que actúan por debajo del nivel de
aplicación y que son más complicados, aunque, afortunadamente, como programadores Java, no
será necesario tener excesivo conocimiento de los protocolos de bajo nivel; nada que vaya más
allá del conocimiento de su existencia.
Capas de Red
Las redes están separadas lógicamente en capas, o niveles, o layers; desde el nivel de aplicación
en la parte más alta hasta el nivel físico en la parte más baja. Porque al presentarse un problema
de tamaño considerable, la solución más óptima comienza por dividirlo en pequeñas secciones,
para posteriormente proceder a solventar cada una de ellas independientemente.
El modelo OSI
El estándar internacional para Sistemas Abiertos de Interconexión, OSI (por su sigla en inglés:
Open Systems Interconnection), se define en el documento ISO/IEC 7498-1, emanado de la
International Standards Organization y la International Electrotechnical Comission. El estándar
completo está disponible como publicación “ISO/IEC 7498-1: 1994”, en
http://standards.iso.org/ittf/PubliclyAvailableStandards/x
El modelo OSI divide el tráfico de la red en una cantidad de capas. Cada capa es independiente
de las capas que la rodean y cada una se apoya en los servicios prestados por la capa inferior
mientras que proporciona sus servicios a la capa superior. La separación entre capas hace que sea
fácil diseñar una pila de protocolos (protocol stack) muy elaborada y confiable, tal como la
difundida pila TCP/IP. Una pila de protocolos es una implementación real de un marco de
comunicaciones estratificado. El modelo OSI no define los protocolos que van a usarse en una
red en particular, sino que simplemente delega cada “trabajo” de comunicaciones a una sola capa
dentro de una jerarquía bien definida.
Mientras que la especificación ISO/IEC 7498-1 determina cómo deberían interactuar las capas,
los detalles de la implementación real se dejan al fabricante. Cada capa puede implementarse en
el hardware (es más común para las capas inferiores), o en el software. Siempre y cuando la
interfaz entre capas se adhiera al estándar, los instaladores son libres de usar cualquier medio a
su disposición para construir su pila de protocolos. Esto quiere decir que cualquier capa de un
28
fabricante A puede operar con la misma capa de un fabricante B (suponiendo que las
especificaciones relevantes se implementen e interpreten correctamente).
A continuación, se presenta un breve bosquejo del modelo de redes OSI de siete capas.
Capa Nombre Descripción
7 Aplicación La Capa de Aplicación es la capa con la que la mayoría de los usuarios
tiene contacto, y es el nivel en el que ocurre la comunicación humana. Por
ejemplo, HTTP, FTP, y SMTP son protocolos de la capa de aplicación. El
usuario se ubica por encima de esta capa, interactuando con la aplicación.
2 Enlace de datos Cada vez que dos o más nodos comparten el mismo medio físico (por
ejemplo, varios computadores conectados a un concentrador (hub), o una
habitación llena de dispositivos inalámbricos que usan el mismo canal de
radio), usan la Capa de Enlace de Datos para comunicarse. Los
ejemplos más comunes de protocolos de enlace de datos son Ethernet,
Token Ring, ATM, y los protocolos de redes inalámbricas (802.11a/b/g).
La comunicación en esta capa se define como de enlace-local porque todos
los nodos conectados a esta capa se comunican directamente entre sí. Esta
capa también se conoce como capa de Control de Acceso al Medio (MAC
en inglés). En redes modeladas de acuerdo con Ethernet, los nodos se
identifican por su dirección MAC. Esta es un número exclusivo de 48 bits
asignado de fábrica a todo dispositivo de red.
Las capas de este modelo están numeradas del 1 al 7, con el 7 en el tope. Esto se hace para
reforzar la idea de que cada capa está basada y depende de la capa de abajo. Imagine el modelo
OSI como un edificio, con sus bases en la capa 1. Las próximas capas, como los pisos sucesivos,
29
y el techo, como la capa 7. Si se remueve una sola capa, el edificio no se sostiene. De manera
semejante, si se incendia el piso 4, nadie podría atravesarlo en ninguna de las dos direcciones.
Las primeras tres capas (Física, Enlace de Datos y Red) ocurren todas “en la red”. Es decir, la
actividad en estas capas va a estar determinada por la configuración de los cables, conmutadores,
enrutadores y otros dispositivos semejantes. Un conmutador (switch) de red puede distribuir
paquetes usando sólo direcciones MAC, así que necesita implementar sólo las capas 1 y 2. Un
enrutador sencillo puede enrutar paquetes usando sólo sus direcciones IP, así que necesita
implementar sólo las capas 1 a 3. Un servidor web o un computador portátil (laptop) ejecutan
aplicaciones, así que deben implementar las siete capas. Algunos enrutadores avanzados pueden
implementar desde la capa 4 en adelante lo que les permite tomar decisiones basadas en la
información de alto nivel contenida en un paquete, como el nombre de un sitio web, o los
adjuntos de un correo electrónico.
Internet dispone de un modelo más sencillo; no define nada en cuanto al aspecto físico de los
enlaces, o a la topología o clase de red de sus subredes y, por lo tanto, dentro del modelo OSI,
sólo existe una correlación con los niveles superiores.
La figura siguiente muestra la correlación existente entre el modelo teórico de capas o niveles de
red propuestos por OSI, y el modelo empleado por las redes TCP/IP.
30
Las aplicaciones que trabajan a un cierto nivel o capa, sólo se comunican con sus iguales en los
sistemas remotos, es decir, a nivel de aplicación, un navegador sólo se entiende con un servidor
Web, sin importarle para nada cómo le llega la información. Este mismo principio es el que se
emplea para el resto de las capas.
1. En primer lugar, que TCP/IP opera sólo en los niveles superiores de red, resultándole
indiferente el conjunto de protocolos que se entienden con los adaptadores de red Token
Ring, Ethernet, ATM, etc., que se encuentren por debajo.
2. En segundo lugar, que IP es un protocolo de datagramas que proporciona un interfaz
estándar a protocolos superiores. Y,
3. En tercer lugar, que dentro de estos protocolos superiores se incluyen TCP y UDP, los
cuales ofrecen prestaciones adicionales que ciertas aplicaciones de red necesitan.
El protocolo de Internet se utiliza por debajo del Nivel de Aplicación y es el encargado de mover
datos en forma de paquetes entre un origen (servidor) y un destino (cliente) y que, como bien
indica su nombre, es el protocolo que normalmente se utiliza en Internet.
Todo dispositivo conectado a Internet o a cualquier red basada en TCP/IP, posee al menos una
dirección IP, un identificador que define unívocamente al dispositivo que lo tiene asignado en la
red.
IP opera entre un sistema local conectado a Internet y su router o encaminador más próximo, así
como entre los distintos encaminadores que forman la red. Cuando un datagrama llega a un
encaminador, éste determina, a partir de su dirección IP de destino, hacia cuál de sus conexiones
de salida ha de dirigir el datagrama que acaba de recibir. Por desgracia, en cuanto al transporte,
IP provee un servicio que intenta entregar los datos al equipo destino, pero no puede garantizar
la integridad, e incluso la recepción de esos datos. Por ello, la mayoría de las aplicaciones hacen
uso de un protocolo de más alto nivel que ofrezca el grado de fiabilidad necesario.
Cada datagrama IP es independiente del resto, por lo que cada uno de ellos es llevado a su
destino por separado. La longitud del datagrama es variable, pudiendo almacenar hasta 65
31
Kbytes de datos; si el paquete de datos (TCP o UDP) sobrepasa ese límite, o el tamaño de la
unidad de datos de la red que se encuentra por debajo es más pequeño que el datagrama IP, el
mismo protocolo IP lo fragmenta, asignándole un número de orden, y distribuye empleando el
número de datagramas que sea necesario.
Por lo tanto, es habitual la utilización de los dos acrónimos juntos, TCP/IP, ya que los dos
protocolos constituyen un método más fiable de encapsular un mensaje en paquetes, de enviar
los paquetes a un destinatario, y de reconstruir el mensaje original a partir de los paquetes
recibidos.
TCP, en resumen, ofrece un servicio de transporte de datos fiable, que garantiza la integridad y
entrega de los datos entre dos procesos o aplicaciones de máquinas remotas. Es un protocolo
orientado a la conexión, en primer lugar, el equipo local solicita al remoto el establecimiento de
un canal de comunicación; y solamente cuando ese canal ha sido creado, y ambas máquinas
están preparadas para la transmisión, empieza la transferencia de datos real.
UDP es un protocolo menos fiable que el TCP, ya que no garantiza que una serie de paquetes
lleguen en el orden correcto, e incluso no garantiza que todos esos paquetes lleguen a su destino.
Los procesos que hagan uso de UDP han de implementar, si es necesario, sus propias rutinas de
verificación de envío y sincronización. Esto porque hay ocasiones en las que no se quiere
incurrir en una sobrecarga del sistema o en la introducción de retrasos por causa de cumplir esas
garantías.
Por ejemplo, si un ordenador está enviando la fecha y la hora a otro ordenador cada 100
milisegundos para que la presente en un reloj digital, es preferible que cada paquete llegue lo
más rápidamente posible, incluso aunque ello signifique la pérdida de algunos de los paquetes.
Como programador Java, el lector tiene en sus manos la elección del protocolo que va a utilizar
en sus comunicaciones, en función de las características de velocidad y seguridad que requiera la
comunicación que desea establecer.
Dirección IP
Cada ordenador o dispositivo conectado a una red TCP/IP dispone de una dirección IP única de 4
bytes (32 bits) para IPv4 (6 bytes (48 bits) para IPv6), en donde, según la clase de red que se
32
tenga y la máscara, parte de los 4 bytes representan a la red, parte a la subred (donde proceda) y
parte al dispositivo final o nodo específico de la red. Por ejemplo, la figura siguiente muestra la
representación de los distintos números de una dirección IP de un nodo perteneciente a una
subred de clase B (máscara 255.255.0.0) para IPv4.
Por razones administrativas, en los primeros tiempos del desarrollo del protocolo IP, se
establecieron cinco rangos de direcciones, dentro del rango total de 32 bits de direcciones IP
disponibles para IPv4, denominando a esos subrangos, clases. Cuando una determinada
organización requiere conectarse a Internet, solicita una clase, de acuerdo al número de nodos
que precise tener conectados a la Red. La administración referente a la cesión de rangos la
efectúa InterNIC (Internet Network Information Center), aunque existen autoridades que, según
las zonas, gestionan dominios locales.
Los subrangos se definen en orden ascendente de direcciones IP, por lo cual, a partir de una
dirección IP es fácil averiguar el tipo de clase de Internet con la que se ha conectado. El tipo de
clase bajo la que se encuentra una dirección IP concreta viene determinado por el valor del
primer byte de los cuatro que la componen o, lo que es igual, el primer número que aparece en la
dirección IP. Las clases toman nombre de la A a la E, aunque las más conocidas son las A, B y
C.
• Las redes clase A. Son las que comienzan con un número entre el 1 y el 126, que permiten
otorgar el mayor número de direcciones IP (16,7 millones), por lo que se asignan a grandes
instituciones educativas o gubernamentales.
• Las redes clases B. (65536 direcciones por clase), suelen concederse a grandes empresas o
corporaciones y, en general, a cualquier organización que precise un importante número de
nodos.
• Las redes clase C. (256 direcciones) son las más comunes y habitualmente se asignan sin
demasiados problemas a cualquier empresa u organización que lo solicite.
• La red clase D. Se reserva a la transmisión de mensajes de difusión múltiple (multicast).
• La red clase E. Es la destinada a investigación y desarrollo.
33
Todo lo dicho antes solamente implica a la asignación de direcciones dentro de Internet. Si se
diseña una red TCP/IP que no vaya a estar conectada a la Red, se puede hacer uso de cualquier
conjunto de direcciones IP. Solamente existen cuatro limitaciones, intrínsecas al protocolo, a la
hora de escoger direcciones IP, pero que reducen en cierta medida el número de nodos
disponibles por clase que se indicaban en la tabla anterior. Estas 4 limitaciones son:
1. La primera es que no se pueden asignar direcciones que comiencen por 0; dichas direcciones
hacen referencia a nodos dentro de la red actual.
2. La segunda es que la red 127 se reserva para los procesos de resolución de problemas y
diagnosis de la red; de especial interés resulta la dirección 127.0.0.1, bucle interno
(loopback) de la estación de trabajo local.
3. La tercera consiste en que las direcciones IP de nodos no pueden terminar en 0, o en
cualquier otro valor base del rango de una subred; porque es así como concluyen las redes.
4. La cuarta, cuando se asignan direcciones a nodos, no se pueden emplear el valor 255, o
cualquier otro valor final del rango de una subred. Este valor se utiliza para enviar mensajes a
todos los elementos de una red (broadcast); por ejemplo, si se envía un mensaje a la dirección
192.168.37.255, se estaría enviando en realidad a todos los nodos de la red de clase C
192.168.37.xx.
Ahora bien, si se quiere que una red local tenga acceso exterior, hay una serie de restricciones
adicionales, por lo que hay una serie de direcciones reservadas que, a fin de que pudiesen ser
usadas en la confección de redes locales, fueron excluidas de Internet. Estas direcciones se
muestran en la siguiente tabla:
Para la creación de una intranet, se debería escoger direcciones IP para la red dentro de alguno
de los rangos reservados de la tabla anterior, y emplear un servidor proxy, o cualquier otro
mecanismo que enmascare las direcciones IP de esa intranet, de forma que todos los puestos de
la red local utilicen una única dirección IP a la hora de salir a la Red.
34
Dominios
El dominio, está constituido por una cadena de caracteres, que es mucho más fácil de recordar
para los humanos, que un número de dirección IP. Así, el dominio para la dirección IP
204.160.241.98 es java.sun.com.
El Sistema de Nombres de Dominio (DNS, Domain Name System) fue desarrollado para realizar
la conversión entre los dominios y las direcciones IP. De este modo, cuando el lector entra en
Internet a través de su navegador e intenta conectarse con un dominio determinado, el navegador
se comunica en primer lugar con un servidor DNS para conocer la dirección IP numérica
correspondiente a ese dominio. Esta dirección numérica IP, y no el nombre del dominio, es la
que va encapsulada en los paquetes y es la que utiliza el protocolo Internet para enrutar estos
paquetes desde el ordenador del lector hasta su destino.
WWW es una sigla que significa: World Wide Web (Red informática mundial, es un sistema de
distribución de documentos de hipertexto o hipermedia interconectados y accesibles vía Internet
– Web Mundo Amplio). El prefijo WWW al comienzo de las direcciones web debido a la
costumbre de nombrar a los host de Internet (los servidores) con los servicios que proporcionan.
De esa forma, por ejemplo, el nombre de host para un servidor web normalmente es "WWW",
para un servidor FTP se suele usar "ftp", y para un servidor de noticias, USENET, "news" o
"nntp" (en relación al protocolo de noticias NNTP). Estos nombres de host aparecen como
subdominio de DNS, como en "www.example.com".
El uso de estos prefijos no está impuesto por ningún estándar, de hecho, el primer servidor web
se encontraba en "nxoc01.cern.ch"29 e incluso hoy en día existen muchos sitios Web que no
tienen el prefijo "www". Este prefijo no tiene ninguna relación con la forma en que se muestra el
sitio web principal. El prefijo "www" es simplemente una elección para el nombre de
subdominio del sitio web.
Servicios y Puertos
Un servicio es una facilidad que proporciona el sistema, y cada uno de estos servicios está
asociado a un puerto.
Un puerto es una dirección numérica a través de la cual se procesa el servicio, es decir es una
dirección lógica proporcionada por el sistema operativo para poder responder.
35
Sobre un sistema Unix, por ejemplo, los servicios que proporciona ese sistema y los puertos
asociados por los cuales responde a cada uno de esos servicios, se indican en el archivo
/etc/services, y algunos de ellos son:
Puerto/Protocolo que
Nombre del servicio Alias del servicio
está asociado al servicio
daytime 13/udp
ftp 21/tcp
telnet 23/tcp telnet
smtp 25/tcp mail
http 80/tcp
Las comunicaciones de información relacionada con Web tienen lugar a través del puerto 80
mediante protocolo TCP. Para emular esto en Java, se utiliza la clase Socket. La fecha (daytime),
sin embargo, el servicio que coge la fecha y la hora del sistema, está ligado al puerto 13
utilizando el protocolo UDP. Un servidor que lo emule en Java usaría un objeto
DatagramSocket.
Teóricamente hay 65535 puertos disponibles, aunque antiguamente los puertos del 1 al 1023 (en
la actualidad también sobrepasan a 1023) están reservados al uso de servicios estándar
proporcionados por el sistema, quedando el resto libre para utilización por las aplicaciones de
usuario.
De no existir los puertos, solamente se podría ofrecer un servicio por máquina. Nótese que el
protocolo IP no sabe nada al respecto de los números de puerto, al igual que TCP y UDP no se
preocupan en absoluto por las direcciones IP.
Se puede decir que IP pone en contacto las máquinas, TCP y UDP establecen un canal de
comunicación entre determinados procesos que se ejecutan en tales equipos y, los números de
puerto se pueden entender como números de oficinas dentro de un gran edificio. El edificio
(equipo), tendrá una única dirección IP, pero dentro de él, cada tipo de negocio, en este caso
HTTP, FTP, etc., dispone de una oficina individual.
Servidores Proxy
Un servidor proxy actúa como interfaz entre los ordenadores de la red interna de una empresa e
Internet. Frecuentemente, el servidor proxy tiene posibilidad de ir almacenando un cierto número
de páginas web temporalmente en caché, para un acceso más rápido. Esto reduce en gran medida
el tiempo de espera por la descarga de la página y el tráfico, tanto dentro como fuera de la
empresa.
protocolo://nombre_servidor[:puerto]/directorio/archivo#referencia
En donde:
http://members.es.tripod.de/froufe/index.html
http://members.es.tripod.de/froufe/
Además de indicar el archivo o página a la que se desea acceder, también es posible indicar una
referencia, que se haya establecido dentro de esa página.
37
4.3. Sockets
Los sockets son puntos finales de enlaces de comunicaciones entre procesos. Los procesos los
tratan como descriptores de archivos, de forma que se pueden intercambiar datos con otros
procesos transmitiendo y recibiendo a través de sockets.
El tipo de sockets describe la forma en la que se transfiere información a través de ese socket, a
continuación, se describe cada uno:
Es un servicio orientado a conexión, donde los datos se transfieren sin encuadrarlos en registros
o bloques. Si se rompe la conexión entre los procesos, éstos serán informados de tal suceso para
que tomen las medidas oportunas.
Es un servicio de transporte sin conexión, más eficientes que TCP, pero en su utilización no está
garantizada la fiabilidad. Los datos se envían y reciben en paquetes, cuya entrega no está
garantizada. Los paquetes pueden ser duplicados, perdidos o llegar en un orden diferente al que
se envió.
El protocolo de comunicaciones con datagramas es un protocolo sin conexión, es decir, cada vez
que se envíen datagramas es necesario enviar el descriptor del socket local y la dirección del
socket que debe recibir el datagrama. Como se puede ver, hay que enviar datos adicionales cada
vez que se realice una comunicación.
La ventaja es que se pueden acceder direcciones globales y el mismo mensaje llegará a muchas
máquinas a la vez.
38
3. Sockets Raw
Son sockets que dan acceso directo a la capa de software de red subyacente o a protocolos de
más bajo nivel. Se utilizan sobre todo para la depuración del código de los protocolos.
1. En UDP, cada vez que se envía un datagrama, hay que enviar también el descriptor del
socket local y la dirección del socket que va a recibir el datagrama, luego los mensajes
son más grandes que los TCP. Como el protocolo TCP está orientado a conexión, hay que
establecer esta conexión entre los dos sockets antes de nada, lo que implica un cierto
tiempo empleado en el establecimiento de la conexión, que no es necesario emplear en
UDP.
2. En UDP hay un límite de tamaño de los datagramas, establecido en 64 kilobytes, que se
pueden enviar a una localización determinada, mientras que TCP no tiene límite; una vez
que se ha establecido la conexión, el par de sockets funciona como los streams: todos los
datos se leen inmediatamente, en el mismo orden en que se van recibiendo.
3. UDP es un protocolo desordenado, no garantiza que los datagramas que se hayan enviado
sean recibidos en el mismo orden por el socket de recepción. Al contrario, TCP es un
protocolo ordenado, garantiza que todos los paquetes que se envíen serán recibidos en el
socket destino en el mismo orden en que se han enviado.
4. Los datagramas son bloques de información del tipo lanzar y olvidar. Para la mayoría de
los programas que utilicen la red, el usar un flujo TCP en vez de un datagrama UDP es
más sencillo y hay menos posibilidades de tener problemas. Sin embargo, cuando se
requiere un rendimiento óptimo, y está justificado el tiempo adicional que supone realizar
la verificación de los datos, la comunicación a través de sockets TCP es un mecanismo
realmente útil.
5. En resumen, TCP parece más indicado para la implementación de servicios de red como
un control remoto (rlogin, telnet) y transmisión de archivos (ftp); que necesitan transmitir
datos de longitud indefinida. UDP es menos complejo y tiene una menor sobrecarga
sobre la conexión; esto hace que sea el indicado en la implementación de aplicaciones
cliente/servidor en sistemas distribuidos montados sobre redes de área local.
39
CARACTERÍSTICAS TCP UDP
Conexión de transmisión SI NO
Transferencia ordenada de los datagramas SI NO
Confiabilidad de transferencia de los datagramas SI NO
Más sencillo y menos posibilidad de tener problemas SI NO
Rendimiento óptimo y verificación de datos SI NO
Servidores de red SI NO
Límite de tamaño de los datagramas NO SI
El mecanismo de sockets está diseñado para ser todo lo genérico posible. El socket por sí mismo
no contiene información suficiente para describir la comunicación que se establece entre
procesos. Los sockets operan dentro de dominios de comunicación, entre ellos se define si los
dos procesos que se comunican se encuentran en el mismo sistema o en sistemas diferentes y
cómo pueden ser direccionados.
Dominio Internet
1. Los sockets stream permiten a los procesos comunicarse a través de TCP. Una vez
establecidas las conexiones, los datos se pueden leer y escribir a/desde los sockets como
un flujo (stream) de bytes. Algunas aplicaciones de servicios TCP son:
2. Los sockets datagrama permiten a los procesos utilizar el protocolo UDP para
comunicarse hacia, y desde, esos sockets por medio de bloques. UDP es un protocolo no
fiable y la entrega de los paquetes no está garantizada. Algunos de los servicios UDP son:
3. Los sockets raw proporcionan acceso al Internet Control Message Protocol, ICMP, y se
utiliza para comunicarse entre varias entidades IP.
40
4.5. Las clases para la programación
Para poder ejecutar los próximos programas es necesario estar conectado en una red, o a Internet,
para que funcionen correctamente, aunque es posible que también pueda hacerse sobre el mismo
ordenador si el lector usa un sistema operativo que lo soporte, Linux por ejemplo; en cualquier
otro caso, el resultado de la ejecución del ejemplo será una triste UnknownHostException.
localhost se utiliza para describir el ordenador local, la máquina en la que se está ejecutando la
aplicación, servidor. Cuando se conecta a una red IP, el ordenador local debe tener una dirección
IP, que se la puede conseguir de diferentes formas:
1. La clase InetAddress
La clase InetAddress proporciona objetos que se pueden utilizar para manipular tanto
direcciones IP como nombres de dominio; sin embargo, no se pueden instanciar estos objetos
directamente. La clase proporciona varios métodos estáticos que devuelven un objeto de tipo
InetAddress, a continuación se indican algunos.
En resumen, la clase InetAddress obtiene la dirección IP real de la red en que se está ejecutando
una aplicación, también se pueden realizar llamadas a los métodos getLocalHost() y
getAddress(). El método getLocalHost() devuelve un objeto InetAddress, que si se usa con
getAddress() generará un array con la dirección IP.
2. La clase URL
41
puede establecer una conexión con cualquier recurso que se encuentre en Internet, especificando
un objeto URL y simplemente invocando el método getContent() sobre ese objeto URL.
La clase URL también proporciona una forma alternativa de conectar un ordenador con otro y
compartir datos, basándose en streams.
Así que se podrían especificar todos los componentes de una dirección URL como en:
URL( "http","www.yahoo.com","80","index.html" );
o dejar que los sistemas utilicen todos los valores por defecto que tienen definidos, como en:
URL( "http://www.yahoo.com" );
3. La clase URLConnection
Es una clase abstracta que puede ser extendida, con un constructor protegido que admite un
objeto URL como parámetro. Tiene unas ocho variables que contienen información muy útil
sobre la conexión que se haya establecido y cerca de cuarenta métodos que se pueden utilizar
para examinar y manipular el objeto que se crea con la instanciación de la clase.
Una forma habitual de conseguir un objeto de tipo URLConnection es invocar un método sobre
un objeto URL que devuelva un objeto de una subclase de la clase URLConnection, que es lo
que muestra el ejemplo.
42
Y, ya solamente queda como interesante el fragmento de código que se usa para invocar a
• Socket. Se puede usar para crear tanto clientes como servidores, representando
comunicaciones TCP
• DatagramSocket. Se puede usar para crear tanto clientes como servidore, representando
comunicaciones UDP
• ServerSocket, No es tan empleada y solamente se utiliza para implementar servidores.
La programación con sockets es una aproximación de bastante bajo nivel para la comunicación
entre dos ordenadores que van a intercambiar datos. Uno de ellos será el cliente y el otro el
servidor.
Aunque la distinción entre cliente y servidor se va haciendo menos clara cada día, en Java hay
una clara diferencia que es inherente al lenguaje:
El hecho de que dos ordenadores puedan conectarse no significa que puedan comunicarse, es
decir, que además de establecerse la conexión, las dos máquinas deben utilizar un protocolo
entendible por ambas para poder entenderse.
43
La programación de sockets en el mundo Unix viene de muy antiguo, Java simplemente
encapsula mucha de la complejidad de su uso en clases, permitiendo un acercamiento a esa
programación mucho más orientado a objetos de lo que podía hacerse antes.
Básicamente, la programación de sockets hace posible que el flujo de datos se establezca en las
dos direcciones entre cliente y servidor, por ello lo de comentar que la diferencia entre cliente y
servidor, una vez establecida la conexión, se diluye. El flujo de datos que se intercambian cliente
y servidor se puede considerar de la misma forma que cuando se guardan y recuperan datos de
un disco: como un conjunto de bytes a través de un canal. Y como en todo proceso en el que
intervienen datos, el sistema es responsable de llevar esos datos desde su punto de origen al
destinatario, y es responsabilidad del programador el asignar significado a esos datos.
Un protocolo a nivel de aplicación es un conjunto de reglas a través de las cuales los programas
que se ejecutan en los dos ordenadores pueden establecer una conversación e intercambiarse
datos.
Es muy sencilla la utilización de sockets para establecer la comunicación entre cliente y servidor;
en realidad, no es más complicada que lo que pueda serlo el escribir datos en un archivo. Enviar
y recoger los datos que se intercambian es la parte fácil del asunto; porque más allá de esto ya se
encuentra el protocolo de comunicación que debe ser entendido por cliente y servidor, que en
caso de ser necesario implementarlo, se convierte ya en algo mucho más complicado.
44
1. Cliente Eco
2. Cliente Fecha
3. Cliente HTTP
4. Cliente SMTP
1. Cliente Eco
El programa comienza instanciando un objeto de tipo String que contiene el nombre del servidor
que se va a utilizar, seguido por la declaración e inicialización de la variable que guarda el
número del puerto, que en el caso del servidor estándar de echo es el 7. A continuación ya se
abren los canales de entrada y salida desde el socket que se mapean en las clases Reader y
Writer. Una vez que se ha establecido la conexión y los canales de entrada y salida están listos
para usarlos, el programa envía una línea de texto al puerto de eco del servidor. Esto hace que el
servidor reenvíe esa misma línea de vuelta al cliente, y el programa la leerá y presentará en
pantalla.
Este programa es muy simple, y solamente trata de enviar una línea de texto al puerto 7, que es el
puerto de ECO, al servidor con el que se establece la conexión. El programa declara las variables
necesarias, luego establece la conexión con el puerto 7 del servidor y abre los canales de entrada
y salida a través de los cuales se va a comunicar. Una vez que estén listos envía la línea de texto
al servidor, que la devuelve al cliente, y lo que se hace aquí es presentar la respuesta del servidor
en la pantalla.
import java.net.*;
import java.io.*;
import java.util.*;
class java2005 {
public static void main( String[] args ) {
String servidor = "localhost";
int puerto = 7; // puerto echo
try {
// Abrimos un socket conectado al servidor y al
// puerto estandar de echo
Socket socket = new Socket( servidor,puerto );
45
// Recogemos la linea devuelta por el servidor y la
// presentamos en pantalla
System.out.println( entrada.readLine() );
// Cerramos el socket
socket.close();
} catch( UnknownHostException e ) {
e.printStackTrace();
System.out.println(
"Debes estar conectado para que esto funcione bien." );
} catch( IOException e ) {
e.printStackTrace();
}
}
}
En caso de que se seleccione un servidor que no tenga soporte para el protocolo echo en el
puerto 7, la salida que generará el programa será diferente que la que cabría esperar. Por
ejemplo, si el lector intenta ejecutar este programa contra el servidor "www.whitehouse.net", la
respuesta que obtendrá será un rechazo de la conexión, algo así como "connection refused.".
Como se puede ver en el listado, el método main() es el que contiene todo el código de la clase,
porque es muy sencillo y no merece la pena desglosarlo. Las dos primeras líneas que hay que ver
del ejemplo son las que contienen las variables a las que se asigna el nombre del servidor al que
se va a conectar y el número del puerto de ese servidor que se va a atacar.
El resto del programa se encuentra englobado en un bloque try/catch para tratar las excepciones.
La línea siguiente es la clave del programa, en ella se establece una conexión con el puerto
indicado del servidor que se ha designado para instanciar un nuevo objeto de tipo Socket
Una vez que este objeto existe, ya es posible realizar la comunicación con el servidor utilizando
el protocolo que tenga predefinido para el servido que proporciona a través de ese puerto. Lo
siguiente destacar en el código del ejemplo es el uso de las clases Reader y Writer, que se
incorporaron en el JDK 1.1.
46
El parámetro true de la última línea hace que el canal de salida realice una descarga o limpieza
de su contenido automáticamente. La realización de esta descarga o vaciado automático de los
canales, es algo de vital importancia a la hora de la programación con sockets.
Y ya lo que resta del código del ejemplo es solamente el uso del canal de salida para enviar a
línea de texto al servidor de eco, la recogida de su respuesta a través del canal de entrada y el
cierre del socket, una vez presentada la cadena devuelta por el servidor.
Y esto es todo lo que hay sobre sockets desde el punto de vista de la parte cliente, no piense el
lector que la complejidad es mucho mayor, se haga lo que se haga. Ahora bien, sí que la
programación de sockets se puede complicar, pero todos los problemas van a venir asociados a la
necesidad de implementar un protocolo a nivel de aplicación para comunicarse correctamente
con el servidor, no del uso en sí de los sockets.
2. Cliente Fecha
El ejemplo java2006.java, también implementa un cliente, pero en este caso para acceder el
puerto que proporciona el día y la hora sobre un servidor que dé soporte a este protocolo.
El ejemplo es incluso más sencillo que el ejemplo java2005.java, ya que no es necesario enviar
nada al servidor para obtener respuesta, todo lo que hay que hacer es establecer la conexión. El
código por tanto es bien simple, tal como se muestra en el listado completo que sigue.
Este ejemplo muestra la fecha y hora del servidor local, en comparación con la hora actual de la
máquina en que se esté ejecutando, en este caso también la máquina local. La secuencia del
programa es semejante al ejemplo anterior, solamente que en este caso se conecta al puerto 13
del servidor localhost, que es el puerto estándar para el servicio de fecha. Una vez que se
establece la conexión, no es necesario preguntar nada al servidor, éste, por el mero hecho de
haber establecido la conexión en ese puerto, envía la hora automáticamente. Finalmente se
imprime la fecha y hora de la máquina utilizando la clase Date.
import java.net.*;
import java.io.*;
import java.util.*;
class java2006 {
public static void main( String[] args ) {
String servidor = "localhost";
47
int puerto = 13; // puerto de daytime
try {
// Abrimos un socket conectado al servidor y al
// puerto estandar de daytime
Socket socket = new Socket( servidor,puerto );
System.out.println( "Socket Abierto." );
// Cerramos 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 );
}
}
}
El programa recoge y presenta la hora del servidor "www.espe.edu.ec", y luego presenta la fecha
y hora donde reside el autor (o donde el lector esté ejecutando el programa), por motivos de
comparación solamente.
Socket Abierto.
Hora actual en www.espe.edu.ec:
Mon Nov 19 15:21:08 COT 2018
Hora Actual en Quito, Ecuador:
Mon Nov 19 15:21:08 COT 2018
Como se puede comprobar, hay diferencia en el día debido a las zonas en que se está obteniendo
la fecha. También se puede ver que hay una diferencia de un segundo entre una hora y otra, el
autor sincronizó el reloj de su ordenador con el servidor de tiempo de bernina.ethz.ch, así que
esa diferencia solamente puede ser atribuible a la duración de la transmisión entre el servidor y el
cliente.
La filosofía del programa es muy similar a la del ejemplo del cliente de eco. Se comienza con la
instanciación de un objeto String para contener el nombre del servidor que va a servir la fecha, y
la declaración e inicialización de la variable que va a contener el número del puerto de ese
servidor que se va a atacar, en este caso el puerto 13, que es el puerto estándar para el servicio
daytime.
48
Luego el programa se agencia un canal de entrada a través de la conexión socket que ha
establecido previamente y ya está listo, porque en este caso, la sola conexión es suficiente para
que el servidor envíe la fecha y la hora. Así que, todo lo que hay que hacer ya es leer la línea de
entrada que contiene esa fecha y hora enviada por el servidor. El programa la presenta y también
presenta la fecha y hora actuales de la máquina en que se está ejecutando el programa, para
establecer una comparación con la que se ha llegado a través del socket.
Como no hay diferencias significativas con el ejemplo java2005.java que vayan más allá del uso
del método System.out.println(), no merece la pena detenerse a contar nada del programa, es
suficiente con que el lector lea los comentarios del código.
3. Cliente HTTP
Este ejemplo es un navegador muy simple implementado mediante sockets. Evidentemente las
páginas que se pueden recibir han de ser de lo más sencillas, no obstante, se implementa lo
suficiente del protocolo http para que la recepción sea decente. Hay que estar conectado para que
el programa pueda funcionar, si no se obtiene una excepción de tipo UnknownHostException. La
mayor parte del programa está encerrada en el bloque try/catch que recoge las excepciones. El
programa abre un socket con el servidor y el puerto 80, luego utiliza la clase BufferedReader
junto con la clase InputStreamReader para abrir un canal de entrada desde el socket. Luego se
utiliza la clase PrintWriter junto con la clase OutputStreamWriter para abrir un canal de salida al
socket. La salida se auto libera, lo cual es crítico, ya que si esa salida no se libera, el servidor no
responde, probablemente lo que ocurra es que el servidor no contesta hasta que tenga la
información de la petición completa. El programa, actuando como navegador, cliente http, envía
un comando GET al servidor indicando un camino y un archivo determinados, para que éste
intente encontrarlos y envíeselos de vuelta al cliente. Cuando ya no haya más líneas que leer, se
recibirá un null, lo cual hará que el cliente salga del bucle de entrada y cierre el socket.
import java.net.*;
import java.io.*;
class java2007 {
public static void main( String[] args ) {
String servidor = "www.deee.espe.edu.ec"; // servidor
int puerto = 80; // puerto
try {
// Crea un socket, conectado al servidor y al puerto
// que se indica
Socket socket = new Socket( servidor,puerto );
// Crea el canal de entrada desde el socket
BufferedReader entrada = new BufferedReader(
new InputStreamReader( socket.getInputStream() ) );
// Crea el canal de salida
49
PrintWriter salida = new PrintWriter(
new OutputStreamWriter( socket.getOutputStream() ),true );
// Se cierra el socket
socket.close();
} catch( UnknownHostException e ) {
e.printStackTrace();
System.out.println(
"Debes estar conectado para que esto funcione bien." );
} catch( IOException e ) {
e.printStackTrace();
}
}
}
El programa envía un comando GET, actuando como cliente, al servidor, indicándole el archivo
que desea recibir. Este comando es parte del protocolo HTTP, que provoca la búsqueda en el
servidor del archivo indicado y su envío al cliente. Si el servidor está montado sobre el puerto
con el que se ha establecido la conexión, siempre enviará algo, si encuentra el archivo, enviará su
contenido, y si no lo encuentra o hay algún otro problema, siempre envía un mensaje de error
indicando la circunstancia por la cual el archivo no ha podido ser transferido al cliente.
El programa lee el texto que recibe por el canal de entrada y lo presenta en el dispositivo
estándar de salida, por lo que se verá el código HTML que forma la página, es decir, se verá
como texto normal.
Esta página que se descarga es una página de ejemplo, que no tiene mayor importancia, pero si el
lector tiene curiosidad por saber cómo se ve en un navegador, la imagen siguiente reproduce
exactamente esa página,
Si el lector revisa el código del programa Java, recordará de ejemplos anteriores todo la parte
inicial de declaración de variables para determinar el servidor y puerto al que conectarse y la
apertura de sockets para los canales de entrada y salida. Así que la primera parte de código que
realmente merece la pena revisar es el envío de comandos HTTP al servidor.
Observe el lector, que el árbol de directorios que se indica al servidor para que consiga localizar
el archivo, es relativo a su pseudo-raiz, es decir, relativo al nivel inicial en que se encuentran los
documentos HTML. La petición se realiza simplemente escribiendo el comando en el canal de
salida.
Si el comando GET ha sido enviado correctamente, hay que esperar siempre una respuesta del
servidor, aunque sea un mensaje de error. El siguiente fragmento de código va leyendo texto del
canal de entrada, presentándolo a continuación en la pantalla, cerrando el socket cuando ya no
hay más datos que leer.
51
// En esta cadena se va a ir leyendo el archivo
String linea = null;
// Bucle para leer y presentar la líneas hasta que se
// reciba un null
while( (linea = entrada.readLine()) != null )
System.out.println( linea );
// Se cierra el socket
socket.close();
El resto del código es ya la parte conocida de control de las excepciones. Si el lector desea
incorporar más características a este ejemplo, a fin de convertirlo en un navegador útil; se le
sugiere que revise las especificaciones HTML y escriba un método de presentación al estilo que
normalmente se asocia a la página web. E incluso puede englobar todo el ejemplo en AWT,
proporcionando un interfaz gráfico mediante un área de texto, TextArea, para la parte de
presentación de la página y un campo de texto, TextField, para especificar la dirección del
archivo del servidor que se desea visualizar.
Otra idea de mejora que puede realizar el lector es crear un robot, que comience en una dirección
determinada, descargue los archivos y siga los enlaces de éstos hasta que alcance el nivel más
inferior; aunque para empezar, un programa más seguro sería un robot que siguiese los enlaces
pero no grabase en disco los archivos, sino que de cada uno de ellos, tras analizarlos, descartase
todo aquello que no fuesen enlaces.
4. Cliente SMTP
Ahora se propone otro ejemplo, java2008.java, en este caso para implementar un cliente SMTP
que sea capaz de enviar correo electrónico a cualquier persona de la que se conozca su cuenta de
correo y el servidor en que está localizada.
El programa comienza instanciando un objeto de tipo String que contiene el nombre del servidor
SMTP. Aunque el autor ha probado el programa con su propio servidor, se ha eliminado esta
asignación del código, para evitar el envío de correo no deseado cuando el lector ejecute el
ejemplo. Seguro que resultará muy sencillo al lector obtener la identificación de su propio
servidor y probar el ejemplo enviándose correo a sí mismo. El puerto estándar para el protocolo
SMTP, de correo electrónico, es el 25, que es el valor de inicialización de la variable declarada
para ello.
% java java2008.java
220 landsraad.net ESMTP Sendmail 8.9.1a/8.9.1;
Sun, 3 Jan 1999 10:37:21 +0100 (MET)
52
250 froufe@arrakis.es... Sender ok
250 froufe@arrakis.es... Recipient ok
354 Enter mail, end with "." on a line by itself
El código completo del ejemplo es el que se muestra, aunque si el lector desea utilizarlo deberá
especificar adecuadamente su cuenta de correo y el servidor en donde resida para que la
ejecución del programa sea correcta.
import java.net.*;
import java.io.*;
import java.util.*;
class java2008 {
public static void main( String[] args ) {
String servidor = "mail.espe.edu.ec"; // !!!!!
String usuario = "eagranizo@espe.edu.ec"; // !!!!!
int puerto = 25; // puerto SMTP
try {
// Abrimos un socket conectado al servidor y al
// puerto del protocolo SMTP
Socket socket = new Socket( servidor,puerto );
salida.println( "data" );
System.out.println( entrada.readLine() );
// Cerramos el socket
socket.close();
53
} catch( UnknownHostException e ) {
e.printStackTrace();
System.out.println(
"Debes estar conectado para que esto funcione bien." );
} catch( IOException e ) {
e.printStackTrace();
}
}
}
Si se revisan las partes más interesantes del código, observará el lector que las líneas iniciales
son las más importantes, ya que establecen el servidor de correo electrónico al que se va a enviar
el mensaje y el nombre del usuario en ese servidor, a cuya cuenta se va a enviar el mensaje. El
texto que muestran las líneas siguientes debe ser sustituido por los valores correctos del servidor
y cuenta de correo del lector.
Luego se envía la línea de texto en la que se indica al servidor la cuenta de correo a la que va
destinado el mensaje. De nuevo, se espera la respuesta del servidor y se presenta en la pantalla.
Todo esto sucede suponiendo que no se produce ningún error, y todo funciona como es de
esperar. Si el lector desea escribir un programa más serio, debería incorporar al código la
comprobación de las respuestas que proporciona el servidor, e implementar las acciones
correctivas necesarias en caso de que surgiese algún problema; pero esto requiere un profundo
estudio del protocolo que se escapa a todas luces del alcance de este Tutorial. Se envía la cadena
"data" al servidor y cuando se recibe la respuesta de que está listo para recibir datos, se construye
un mensaje de prueba que se envía, y se concluye con un punto, que es el que indica al servidor
que se ha llegado al final del mensaje.
salida.println( "data" );
System.out.println( entrada.readLine() );
String timeStamp = (new Date()).toString();
salida.println( "Mensaje de prueba "+timeStamp );
salida.println( "." );
System.out.println(entrada.readLine());
Tras esto ya se cierra el socket. El resto del código vuelve a ser el control de las excepciones. Si
el lector se decir a completar el ejemplo, ha de tener en cuenta que la especificación debe seguir
54
escrupulosamente, y que debe examinar cada uno de los mensajes de respuesta del servidor para
confirmar que todo el trasiego de información se está realizando correctamente.
La clase ServerSocket es la que se utiliza a la hora de crear servidores, al igual que, como ya se
ha visto, la clase Socket se utilizaba para crear clientes.
• Uno de los servidores es un servidor "echo" que está implementado a través de un hilo de
ejecución que monitoriza el puerto 7. Este servidor devuelve la cadena que reciba por el
puerto 7 al mismo cliente que la ha enviado.
• El otro servidor es un servidor HTTP abreviado, que se ha implementado a través de un
hilo de ejecución que monitoriza el puerto 80, que es el puerto estándar para el protocolo
HTTP. En este servidor se ha implementado la respuesta al comando GET, que devuelve
al cliente el contenido del archivo que haya solicitado, o un mensaje de error en caso de
no encontrarlo.
• El tercer servidor es un servidor Fecha, que se ha implementado a través de un hilo de
ejecución que monitoriza el puerto 13, solamente responde la clase Date, cualquier otro
comando será ignorado y el cliente obtendrá como respuesta un mensaje de error.
Si el lector ejecuta los ejemplos en entorno Windows, es suficiente con que arranque los
ejemplos como cualquier otro programa Java, antes de lanzar la parte cliente, o al menos antes de
que la parte cliente solicite algo al servidor. Sin embargo, si la ejecución se realiza en entornos
Solaris, Linux, etc. probablemente se encuentre con que no hay permiso para utilizar los puertos
que se asignan en los ejemplos. Esto, como ya se ha indicado, es debido a que los puertos por
debajo del 1024 están reservados para uso del sistema; no obstante, el lector puede cambiar el
número de puerto tanto en el servidor como en el cliente y ejecutarlos.
La parte principal de la aplicación se encuentra en el método main(), que contiene las tres
sentencias que permiten el uso de las clases que implementan el objetivo concreto de la creación
de los servidores.
import java.net.*;
import java.io.*;
import java.util.*;
public class java2009 {
public static void main( String[] args ) {
// Se instancia un objeto servidor para escuchar el puerto 7
ServidorEco servidorEcho = new ServidorEco();
// Se instancia un objeto servidor para la fecha en el puerto 13
ServidorFecha servidorfecha = new ServidorFecha();
// Se instancia un objeto servidor para escuchar el puerto 80
55
ServidorHttp servidorHttp = new ServidorHttp();
}
}
Estos tres servidores se implementan en hilos de ejecución diferentes para que puedan funcionar
en paralelo de forma asíncrona. A continuación, se explican estos servidores:
a. Servidor Eco
Siguiendo con la revisión de las partes interesantes del código del programa que se implementa
en el ejemplo java2009.java, lo que se encuentra el lector ahora es la clase que implementa el
servidor del protocolo Echo, que es el más simple de los dos que se muestran en el programa. En
general, los dos servidores funcionan del mismo modo, corriendo cada uno de ellos en su propio
hilo de ejecución, y escuchando el puerto que corresponde a su protocolo, en espera de
conexiones de clientes. Mientras un servidor se encuentra en este estado de espera de
conexiones, estará bloqueado para consumir el mínimo de recursos del sistema.
56
// Esta clase se utiliza el lanzar un hilo de ejecucion que atienda
// la llamada recibida a traves del puerto 7, el puerto de eco
class ConexionEcho extends Thread {
Socket socket;
// Constructor
ConexionEcho( Socket socket ) {
System.out.println( "Recibida una llamada en el puerto 7" );
this.socket = socket;
// Trabajamos por debajo de la prioridad de los otros puertos
setPriority( NORM_PRIORITY-1 );
// Se arranca el hilo y se pone a correr
start();
}
try {
// Conseguimos un canal de entrada desde el socket
entrada = new BufferedReader( new InputStreamReader(
socket.getInputStream() ) );
// Conseguimos un canal de salida hacia el socket. El canal es
// con liberaci�n autom�tica (autoflush)
salida = new PrintWriter( new OutputStreamWriter(
socket.getOutputStream()),true );
Explicación de la clase
Cuando un cliente requiere una conexión en cualquiera de los dos puertos, el servidor lanza otro
hilo de ejecución para manejar las necesidades del cliente y luego vuelve para seguir escuchando
el puerto en su propio hilo de ejecución. Los hilos de ejecución para dar soporte a los clientes, se
lanzan con prioridad mínima, de forma que estos hilos no interfieran la capacidad asignada a los
servidores de reconocer y responder a cualquier otro cliente que esté solicitando una conexión. Si
hay muchos clientes solicitando conexiones, el servidor que atiende al puerto lanzará un hilo de
ejecución por cada una de esas conexiones (dentro de las capacidades del sistema); de forma que
puede haber muchos hilos ejecutándose simultáneamente, atendiendo cada uno de ellos a las
necesidades de un cliente específico.
La primera sentencia interesante del servidor de eco es el constructor, que simplemente invoca a
su propio método start() que iniciará el arranque de su propio hilo de ejecución.
Y acto seguido, ya se puede realizar la llamada al método accept() para recoger las conexiones
que establezcan los clientes con el servidor a través del puerto que está monitorizando ese
servidor. Las líneas siguientes muestran cómo se hace esto en el ejemplo.
Cuando se instancia un objeto de tipo ServerSocket y se invoca el método accept() sobre ese
objeto, este método bloquea el servidor y se queda a la espera hasta que se produce una conexión
de un cliente en el puerto que controla. Cuando esto sucede, se instancia automáticamente un
objeto Socket que es devuelto por el método accept().
El lector comprobará que hay muchos conceptos que se están repitiendo, y que si va leyendo con
detenimiento, se vuelve sobre ellos una y otra vez. Esto está hecho deliberadamente, ya que hay
una serie de conceptos y métodos muy simples en los que se basa todo el funcionamiento de las
comunicaciones en red con Java, y que son los que verdaderamente tienen que quedar arraigados
en el conocimiento del lector. Por ello, aún a fuer de resultar un poco ladrillo, es preferible recaer
una vez sobre otra en los conceptos que el autor considera fundamentales, para que una vez
concluida la lectura del capítulo, al menos esos conceptos hayan quedado lo suficientemente
claros y grabados en el conocimiento del lector.
El objeto Socket devuelto por el método accept(), se conecta automáticamente con el objeto
Socket utilizado por el cliente que ha establecido la conexión, y se puede utilizar para establecer
la comunicación con el cliente. Esto es muy importante, así que hay que detenerse un poco en
ello.
58
conexión. Este nuevo socket es el devuelto por el método accept() para poder establecer la
comunicación con el socket del cliente.
En el trozo de código anterior, se observa que cuando se recibe una conexión, se lanza un hilo de
ejecución del tipo ConexionEcho que atiende al cliente que ha solicitado esa conexión. Al
constructor de la clase que maneja este nuevo hilo, se le pasa como parámetro el objeto Socket
que el método accept() devuelve, que ya está conectado con el cliente, y a través del cual, el
protocolo de comunicaciones para el servicio, echo en este caso, puede comunicarse con el
cliente.
Observe el lector que el hilo en el cual está corriendo el objeto ServidorEco se encuentra en
medio de un bucle infinito. Luego, una vez que el hilo de ejecución ConexionEcho haya sido
lanzado con éxito, el objeto ServidorEco volverá a su función inicial de seguir esperando a la
conexión de otro cliente a través del puerto de eco.
// Constructor
ConexionEcho( Socket socket ) {
System.out.println( "Recibida una llamada en el puerto 7" );
this.socket = socket;
// Trabajamos por debajo de la prioridad de los otros puertos
setPriority( NORM_PRIORITY-1 );
// Se arranca el hilo y se pone a correr
start();
}
Como puede observar el lector, tras guardar el parámetro en una variable de instancia, el
constructor fija la prioridad del hilo de ejecución. Esto es para que los hilos que están
monitorizando los puertos no se vean interrumpidos por los hilos que están atendiendo a las
conexiones con clientes ya establecidas. Una vez ajustada la prioridad, ya solamente resta
invocar al método start() para que el hilo de ejecución se levante y empiece a correr. Como es
habitual, el método start() invocará al método run() de este hilo de ejecución.
59
System.out.println( "Recibido: "+cadena );
socket.close();
System.out.println( "Socket cerrado" );
Con esto se concluye el repaso al código que implementa el servidor Eco en el programa y se
pasa a discutir la clase que atiende a las conexiones con el puerto estándar del protocolo HTTP.
Aunque este es un caso considerablemente más complejo, gran parte del código es idéntico al
que se acaba de presentar para el caso del servidor Echo.
b. Servidor HTTP
60
// Constructor
ConexionHttp( Socket socket ) {
System.out.println( "Recibida una llamada en el puerto 80" );
this.socket = socket;
// Trabajamos por debajo de la prioridad de los otros puertos
setPriority( NORM_PRIORITY-1 );
// Se arranca el hilo y se pone a correr
start();
}
Explicación de la clase
El método accept(), tal como muestran las líneas de código anteriores, se invoca sobre este
objeto dentro de un bucle infinito para bloquea el servidor y monitorizar el puerto 80, esperando
a que lleguen conexiones de clientes. Cuando esto ocurre, el método accept() instancia y
devuelve un objeto Socket, que ya estará conectado con la máquina cliente.
Este objeto Socket, se pasa como parámetro al constructor de un nuevo objeto de tipo
ConexionHttp, que lanzará un hilo de ejecución específico para atender a la conexión que se ha
establecido con el cliente, a través de la versión abreviada del protocolo HTTP que se ha
implementado en esta clase.
El constructor es similar al visto para el servidor de Eco; así que, en haras de la brevedad no se
incluye aquí. Si el lector sigue el código del ejemplo, no encontrará nada nuevo hasta llegar a la
62
transmisión de información al cliente, que en este caso se hace enviando un array de bytes, algo
no visto hasta ahora. El siguiente fragmento de código muestra la creación del canal de salida
que va a permitir este tipo de comunicación.
Esto se encuentra dentro del método run(), corazón del hilo de ejecución que está atendiendo a la
conexión. A continuación, lo que se espera es la conexión del cliente, para lo que se utiliza el
método readLine() sobre el canal de entrada que lee las peticiones y almacena esa petición en un
objeto String.
Lo siguiente que hay que hacer es el análisis de la petición que ha realizado el cliente para
comprobar si es posible atenderla o no, teniendo en cuenta que solamente se responde al
comando GET. Para realizar este análisis se utiliza un objeto StringTokenizer, que indicará si
hay o no un comando GET en la petición realizada por el cliente.
En caso de que no sea una petición GET, se creará una página dentro del código para devolver el
mensaje de error al cliente. Si la petición sí corresponde a un comando GET, lo que se intenta es
comprobar el nombre del archivo que ha solicitado el cliente y enviárselo; y en caso de que no
solicite ninguno, completar el camino que haya indicado con el archivo index.html, que es el
archivo estándar que utilizan casi todos los navegadores como archivo de defecto en caso de no
especificar una página determinada en el acceso a un sitio Internet. Las siguiente línea de código
elimina la posibilidad de que la petición contenga barras "/" extra.
Si la petición termina con una barra "/" o es una cadena vacía, se supone que el cliente quiere
descargar el archivo index.html; así que, en este caso, se añade este nombre de archivo a la
cadena que contiene la petición realizada por el cliente.
Llegados a este punto, ya se sabe el archivo que hay que enviarle al cliente como respuesta a su
petición, así que se intenta abrir un objeto de tipo FileInputStream con ese nombre de archivo y
en el camino que se indique. Si no se puede conseguir, se lanzará una excepción que será
63
procesada en el bloque catch del final del programa. Si el archivo sí se puede leer, se creará un
array de bytes igual al contenido del archivo y se leerá ahí ese contenido.
Una vez que se ha identificado, localizado y leído el archivo en un array en memoria, el siguiente
paso consiste en el uso del canal de salida que se había creado anteriormente para transmitir el
contenido del array al cliente; concluyendo con la liberación forzada de todo el contenido del
array, tal como se muestra en las siguientes líneas de código.
El siguiente fragmento de código se ejecuta en el caso de que el cliente no envíe una petición
GET, en cuyo caso se crea un documento sobre la marcha conteniendo el mensaje de error que
indica tal circunstancia y se le envía como respuesta al cliente.
} else
// La petición que se ha hecho no es un GET
salida.println( "<HTML><BODY><P>400 Petici&oactute;n "+
"Errónea<P></BODY></HTML>" );
socket.close();
Esta última sentencia cierra el socket y permite que el hilo de ejecución termine normalmente,
siempre asumiendo que no se ha lanzado ninguna excepción entre medio; porque en el caso de
que se hubiese generado alguna excepción, hay varios controladores para recoger estas
excepciones, e incluso algunos, como el lector podrá observar en el código del ejemplo, generan
páginas sobre la marcha que envían al cliente, indicando la circunstancia que ha provocado el
lanzamiento de la excepción que controlan.
}catch( IOException e ) {
e.printStackTrace();
try {
socket.close();
System.out.println( "Socket cerrado" );
}catch( IOException evt ) {
System.out.println(evt);
}
64
anteriormente, pero vamos; es de suponer que funciona, aunque el autor no disponga de ningún
método de comprobación de que eso es así en el momento de redactar este párrafo.
c. Servidor Fecha
// Constructor
ConexionFecha( Socket socket ) {
System.out.println( "Recibida una llamada en el puerto 13" );
this.socket = socket;
// Trabajamos por debajo de la prioridad de los otros puertos
setPriority( NORM_PRIORITY-1 );
// Se arranca el hilo y se pone a correr
start();
}
try {
// Enviamos la fecha
salida.println( new Date() );
socket.close();
System.out.println( "Socket cerrado" );
} catch( IOException e ) {
e.printStackTrace();
}
}
}
Explicación de la Clase
El servidor Fecha es realmente simple, y solamente responde la clase Date, cualquier otro
comando será ignorado y el cliente obtendrá como respuesta un mensaje de error. En esta clase
ServidorFecha se utiliza para instanciar un hilo de ejecución para el servidor que se encarga de
entregar la fecha en el puerto 13, que es el definido como estándar para el protocolo de "fecha".
Este ejemplo es igual que el programa java2005, ya presentado, pero se ha cambiado el servidor
de conexión para poder probar el ejemplo del servidor de eco que se ha planteado en el servidor
de ejemplo del Tutorial. Se trata simplemente de conectarse al servidor y enviar una línea de
texto al puerto 7, que es el puerto de ECO ese servidor. El programa declara las variables
necesarias, luego establece la conexión con el puerto 7 del servidor y abre los canales de entrada
y salida a través de los cuales se va a comunicar. Una vez que están listos envía la línea de texto
al servidor, que la devuelve al cliente, y lo que se hace aquí es presentar la respuesta del servidor
en la pantalla.
import java.net.*;
import java.io.*;
import java.util.*;
class java2010 {
public static void main( String[] args ) {
String servidor = "localhost";
int puerto = 7; // puerto echo
try {
// Abrimos un socket conectado al servidor y al
// puerto est�ndar de echo
66
Socket socket = new Socket( servidor,puerto );
// Cerramos el socket
socket.close();
} catch( UnknownHostException e ) {
e.printStackTrace();
System.out.println(
"Debes estar conectado para que esto funcione bien." );
} catch( IOException e ) {
System.out.println( e );
}
}
}
class java2011 {
public static void main( String[] args ) {
String servidor = "localhost"; // servidor
int puerto = 1080; // puerto
try {
// Crea un socket, conectado al servidor y al puerto
// que se indica
Socket socket = new Socket(servidor,puerto);
// Crea el canal de entrada desde el socket
BufferedReader inputStream =
new BufferedReader( new InputStreamReader(
socket.getInputStream() ) );
// Crea el canal de salida
PrintWriter outputStream =
new PrintWriter( new OutputStreamWriter(
socket.getOutputStream() ),true );
67
// La siguiente sentencia devuelve el archivo que se
// solicite, si se encuentra ahi.
// El lector deberia protegerse contra ello
outputStream.println( "GET E:/AEjercicios/prueba01.html" );
// Se cierra el socket
socket.close();
} catch( UnknownHostException e ) {
e.printStackTrace();
System.out.println(
"Debes estar conectado para que esto funcione bien." );
} catch( IOException e ) {
e.printStackTrace();
}
}
}
Este ejemplo es igual que el programa java2006, que muestra la fecha y hora del servidor local,
en comparación con la hora actual de la máquina en que se esté ejecutando, en este caso también
la máquina local. La secuencia del programa es semejante al ejemplo anterior, solamente que en
este caso se conecta al puerto 13 del servidor "localhost", que es el puerto estándar para el
servicio de fecha. Una vez que se establece la conexión, no es necesario preguntar nada al
servidor, éste, por el mero hecho de haber establecido la conexión en ese puerto, envía la hora
automáticamente. Finalmente se imprime la fecha y hora de la máquina utilizando la clase Date.
import java.net.*;
import java.io.*;
import java.util.*;
class java20110 {
public static void main( String[] args ) {
String servidor = "localhost";
int puerto = 13; // puerto de daytime
try {
// Abrimos un socket conectado al servidor y al
// puerto estándar de echo
Socket socket = new Socket( servidor,puerto );
System.out.println( "Socket Abierto." );
// Cerramos 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 ) {
68
System.out.println( e );
}
}
}
69
6. Cliente y Servidor con Datagrama
6.1. Clientes Datagrama
La clase DatagramPacket, junto con la clase DatagramSocket, son las que se utilizan para la
implementación del protocolo UDP (User Datagram Protocol).
La programación para uso del protocolo UDP se diferencia de la programación para utilizar el
protocolo TCP en que no existe el concepto de ServerSocket para los datagramas y que es el
programador el que debe construirse sus propios paquetes a enviar por UDP.
Para enviar datos a través de UDP, hay que construir un objeto de tipo DatagramPacket y
enviarlo a través de un objeto DatagramSocket, y al revés para recibirlos, es decir, a través de
un objeto DatagramSocket se recoge el objeto DatagramPacket. Toda la información respecto
a la dirección, puerto y datos, está contenida en el paquete.
• Para enviar un paquete, primero se construye ese paquete con la información que se
desea transmitir, luego se almacena en un objeto DatagramSocket y, finalmente se
invoca el método send() sobre ese objeto.
• Para recibir un paquete, primero se construye un paquete vacío, luego se le presenta a
un objeto DatagramSocket para que almacene allí el resultado de la ejecución del
método receive() sobre ese objeto.
Hay que tener en cuenta que el hilo de ejecución encargado de todo esto estará bloqueado en el
método receive() hasta que un paquete físico de datos se reciba a través de la red; este paquete
físico será el que se utilice para rellenar el paquete vacío que se había creado.
También hay que tener cuidado cuando se pone a escuchar a un objeto DatagramSocket en un
puerto determinado, ya que va a recibir los datagramas enviados por cualquier cliente. Es decir,
que si los mensajes enviados por los clientes están formados por múltiples paquetes; en la
70
recepción pueden llegar paquetes entremezclados de varios clientes y es responsabilidad de la
aplicación el ordenarlos.
a. La clase DatagramPacket
Cuando se construye el paquete a enviar, es necesario colocar los datos en el array antes de
llamar al método send(); además de eso, hay que incluir la longitud de ese array y, también se
debe proporcionar un objeto de tipo InetAddress indicando la dirección de destino del paquete y
el número del puerto de ese destino en el cual estará escuchando el receptor del mensaje. Es
decir, que la dirección de destino y el puerto de escucha deben ir en el paquete, al contrario de lo
que pasaba en el caso de TCP que se indicaban en el momento de construir el objeto Socket.
El tamaño físico máximo de un datagrama es 65535 bytes, y teniendo en cuenta que hay que
incluir datos de cabecera, esa longitud nunca está disponible para datos de usuario, sino que
siempre es algo menor.
La clase DatagramPacket proporciona varios métodos para poder extraer los datos que llegan
en el paquete recibido. La información que se obtiene con cada método coincide con el propio
nombre del método, aunque hay algún caso en que es necesario saber interpretar la información
que proporciona ese mismo método. A contuación se describen los diferentes métodos de esta
clase:
71
ejemplos que se ven en este Tutorial utilizan exclusivamente datos de tipo String, pero
esto no es un requerimiento, y se pueden utilizar datagramas para intercambiar cualquier
tipo de datos, siempre que se puedan colocar en un array de bytes en un ordenador y
extraerlos de ese array en la parte contraria. Es decir, que la responsabilidad del sistema
se limita al desplazamiento del array de bytes de un ordenador a otro, y es
responsabilidad del programador el asignar significado a esos bytes.
• El método getLength() devuelve el número de bytes que contiene la parte de datos del
datagrama, y
• El método getOffset() devuelve la posición en la cual empieza el array de bytes dentro
del datagrama completo.
b. La clase DatagramSocket
Un objeto de la clase DatagramSocket puede utilizarse tanto para enviar como para recibir un
datagrama.
La clase tiene tres constructores. Uno de ellos se conecta al primer puerto libre de la máquina
local; el otro permite especificar el puerto a través del cual operará el socket; y el tercero permite
especificar un puerto y una dirección para identificar a una máquina concreta.
Independientemente del constructor que se utilice, el puerto desde el cual se envíe el datagrama,
siempre se incluirá en la cabecera del paquete. Normalmente, la parte del servidor utilizará el
constructor que permite indicar el puerto concreto a usar, ya que si no, la parte cliente no tendría
forma de conocer el puerto por el cual le van a llegar los datagramas.
La parte cliente puede utilizar cualquier constructor, pero por flexibilidad, lo mejor es utilizar el
constructor que deja que el sistema seleccione uno de los puertos disponibles. El servidor debería
entonces comprobar cuál es el puerto que se está utilizando para el envío de datagramas y enviar
la respuesta por ese puerto.
• Para enviar un datagrama, hay que invocar al método send() sobre un socket
datagrama existente, pasándole el objeto paquete como parámetro. Cuando el paquete es
enviado, la dirección y número de puerto del ordenador origen se coloca
automáticamente en la porción de cabecera del paquete, de forma que esa información
pueda ser recuperada en el ordenador destino del paquete.
• Para recibir datagramas, hay que instanciar un objeto de tipo DatagramSocket,
conectarse a un puerto determinado e invocar al método receive() sobre ese socket. Este
72
método bloquea el hilo de ejecución hasta que se recibe un datagrama, por lo que si es
necesario hacer alguna cosa durante la espera, hay que invocar al método receive() en su
propio hilo de ejecución.
Es importante tener en cuenta que los números de puerto TCP y UDP no están relacionados. Se
puede utilizar el mismo número de puerto en dos procesos si uno se comunica a través de
protocolo TCP y el otro lo hace a través de protocolo UDP. Es muy común que los servidores
utilicen el mismo puerto para proporcionar servicios similares a través de los dos protocolos en
algunos servicios estándar, como puede ser el eco.
Esta aplicación no es más que una actualización del ejemplo java2005.java, al que se le incluye
además el protocolo UDP. El ejemplo java2012.java realiza dos pruebas del servicio Echo contra
el mismo servidor, enviando una línea de texto al puerto estándar de este servicio, el puerto 7. En
la primera prueba utiliza el protocolo TCP/IP y en la segunda emplea un datagrama UDP.
Este ejemplo es una mejora del ejemplo java2005, que comprobaba el protocolo de echo. En este
caso también se incluye el echo a través de UDP. El programa realiza dos comprobaciones, la
primera enviando un mensaje al puerto 7 para probar la comunicación TCP/IP, y la segunda es a
través de un datagrama UDP, también a través de ese puerto. La parte TCP es igual al ejemplo
anterior, pero el mensaje que se envía por UDP se convierte a un array de bytes, que estará
contenido en un objeto de tipo DatagramPacket, que además contendrá la dirección del servidor,
que previamente ha obtenido instanciando un objeto de tipo InetAddress, y el número del puerto
de ese servidor. Luego se invoca al método send() del socket, pasándole el paquete como
parámetro, para que sea enviado. Los datos en el paquete se sobrescriben con "x" para confirmar
73
que se reciben datos del paquete, y que no residuo del mensaje anterior. Luego se invoca el
método receive() sobre el objeto DatagramSocket, pasándole el paquete como parámetro, esto
hace que el hilo se bloquee hasta que le llegue el paquete por el mismo puerto por el cual lo ha
enviado. Cuando el paquete original es recibido, los datos en este paquete físico se extraen y
escriben en la parte de datos del objeto que se proporciona como parámetro al método receive().
El hilo se desbloquea y el control del programa sigue con la presentación de los datos que
contenga el paquete en la pantalla que, como era de esperar, coincide con el que se envía
originalmente al puerto de eco del servidor.
import java.net.*;
import java.io.*;
import java.util.*;
class java2012 {
public static void main( String[] args ) {
String servidor = "localhost"; // servidor
int puerto = 7; // puerto eco
String cadTcp = "Prueba de Eco TCP";
String cadUdp = "Prueba de Eco UDP";
// Se cierra el socket
socketDgrama.close();
} catch( UnknownHostException e ) {
e.printStackTrace();
System.out.println(
"Debes estar conectado para que esto funcione bien." );
} catch( SocketException e ) {
e.printStackTrace();
} catch( IOException e ) {
e.printStackTrace();
}
}
}
Se instancian dos objetos de tipo String, para utilizar uno diferente en cada protocolo. Luego
está la parte correspondiente a la prueba de eco a través de TCP, sobre la que no se insiste más.
Una vez cerrado el socket TCP, comienza la prueba de eco a través de UDP.
En primer lugar, se convierte el mensaje que se ha de enviar por UDP a un array de bytes. Hay
que instanciar un objeto de tipo InetAddress que contenga la dirección del servidor con el que
se va a realizar la conexión y el envío del datagrama con el array de bytes recién creado.
Se crea un objeto de tipo DatagramPacket que contenga el array de bytes de la cadena a enviar,
junto con la dirección del servidor y el puerto al que hay que conectarse. Se crea ahora un objeto
de tipo DatagramSocket que será utilizado para enviar el paquete al servidor. Sin embargo, hay
que recordar que el protocolo UDP no garantiza que el paquete llegue íntegro al servidor, o que
tan siquiera llegue.
Los mismos objetos DatagramSocket y DatagramPacket serán los utilizados para recibir el
paquete de respuesta del servidor (siempre que la suerte acompañe). Se usa un bucle para
sobreescribir los datos en el paquete con una letra para poder comprobar que una vez recibido el
paquete de respuesta del servidor de eco, los datos son nuevos y no simplemente el residuo del
mensaje que se había colocado originalmente en el paquete.
Como el ejemplo es una simple actualización de otro de los ejemplos del Tutorial, gran parte del
código ya está más que visto, y es exactamente igual al del ejemplo java2005.java. Así que,
solamente se van a repasar a continuación algunas de las líneas de código más interesantes de la
parte que se aporta nueva en este ejemplo, que corresponderá, evidentemente, a la
implementación del intercambio de mensajes con el servidor a través del puerto del servicio Eco,
pero con protocolo UDP.
El primer fragmento en que hay que detenerse es justo en la declaración del método main(), en
donde se declaran e inicializan algunas variables importantes, cuyo nombre es autoexplicativo,
como se puede comprobar.
Luego está todo el código referente al protocolo TCP, que en este caso no resulta interesante, y
ya se alcanza el punto del programa en el que se convierte el mensaje en un array de bytes, y se
instancia un objeto que identifique al servidor. Se utiliza el método getBytes() de la clase String
para convertir el mensaje a un array de bytes, como se puede ver.
76
para enviar el datagrama al servidor invocando al método send() sobre el objeto
DatagramSocket.
Las siguientes líneas de código son las que sobreescriben los datos del mensaje con una letra,
para el proósito que se ha indicado antes de comprobar que el mensaje que se recibe no es en
realidad el resto del que se ha mandado. Este fragmento de código también muestra al lector
cómo puede acceder a la parte de datos de un objeto DatagramPacket, en caso de que lo
necesite para cualquier otro propósito.
A partir de este punto, se asume que habrá una respuesta del servidor, así que se invoca el
método receive() sobre el mismo objeto DatagramSocket que se ha utilizado para enviar el
mensaje original al servidor. Esto bloquea el thread, o hilo de ejecución, quedando a la espera de
respuesta. Aunque no se ha indicado en ningún sitio, es posible utilizar el método setTimeout()
para indicar la cantidad de tiempo que el método receive() estará a la espera y bloqueando, lo
cual permite colocar una protección al programa para que no se quede colgado esperando una
respuesta que no llegue jamás.
Y el resto del código del ejemplo es la presentación en pantalla del mensaje recibido del
servidor, que debe coincidir con el enviado, y el código de manejo de excepciones.
Como el programa es una actualización del ejemplo java2009.java, el lector deberá tener en
cuenta las mismas advertencias que se realizaban al respecto de ese ejemplo, sobre todo en lo
que se refiere al agente de seguridad, en caso de que decida utilizar el ejemplo para sus propios
propósitos. Aquí solamente se muestra como ilustración de lo que se puede hacer, no para que se
haga uso de él para cualquier otro menester.
77
En el ejemplo se implementan tres servidores:
• Uno de ellos es un servidor Eco UDP implementado a través de un hilo de ejecución que
monitoriza un DatagramSocket sobre el puerto 7. Este servidor devuelve el array de
bytes que llegue en cada datagrama que reciba, enviando esos datos de regreso al cliente
que haya originado el mensaje.
• El segundo servidor es un servidor Eco TCP implementado a través de un hilo de
ejecución que monitoriza un ServerSocket sobre el puerto 7. Este servidor también
devuelve los datos que recibe al cliente que haya realizado la conexión.
• El tercer servidor es un servidor HTTP muy simple implementado a través de un hilo de
ejecucicón TCP que monitoriza el puerto 80. Este servidor solamente responde al
comando GET que se envíe desde un navegador, y enviar un archivo como un stream de
bytes.
La inclusión de estos tres tipos de servidores es para mostrar al lector la forma en que se pueden
utilizar los hilos de ejecución para dar servicio a múltiples puertos, haciendo además una mezcla
de protocolos TCP y UDP.
La parte del servidor HTTP se puede comprobar a través de un navegador indicando localhost
como nombre del servidor, y los otros servidores se pueden chequear mediante el ejemplo
java2014.java, que ha sido pensado específicamente para probar los servidores Eco instalados en
la propia máquina en que se ejecuten cliente y servidor. El código completo del ejemplo es el
que se muestra a continuación.
En este ejemplo mejora el ejemplo java2009 añadiéndole soporte para el protocolo echo a través
del puerto 7, pero a través de datagramas UDP. En el ejemplo se implementan tres servidores
diferentes sobre red IP, y solamente se pretende que sea ilustrativo, no para utilizarlo como algo
serio. Si se hace así, el autor declina toda responsabilidad.
El hecho de que se implementen los dos servidores a la vez, sobre distintos puertos, ilustra
también la forma en que se puede utilizar el mecanismo de los hilos de ejecución que
proporciona Java para servir a múltiples puertos, y en este caso, también muestra como en un
mismo programa se pueden mezclar comunicaciones TCP y UDP. Hay un controlador de
seguridad implementado, para prevenir que el servidor envíe algún archivo no deseado.
78
Solamente está autorizado a servir los archivos que se encuentren en el directorio actual y sus
subdirectorios. De otra forma, el servidor estará abierto y cualquiera podrá solicitar cualquier
archivo del disco. Cuidado si se instala en una red y se deja desatendido, porque se pueden
conectar clientes y tomar el control del ordenador, o hacer cosas extrañas. La parte HTTP del
programa se puede comprobar utilizando cualquier navegador indicando que el servidor es
"localhost". También se puede comprobar utilizando el ejemplo Sockets06, que está pensado
para testear específicamente el controlador de seguridad que se ha instalado en este ejemplo. La
parte de "echo" se puede comprobar con el programa Sockets05, pensado específicamente para
ese propósito, realizando test tanto de la porción UDP como de la porción TCP del programa.
import java.net.*;
import java.io.*;
import java.util.*;
try {
// Abrimos un socket datagrama
socketDgrama = new DatagramSocket();
// Se utiliza el nuevo socket datagrama para enviar el mensaje
// y cerrar el socket
socketDgrama.send( paqueteEnvio );
socketDgrama.close();
System.out.println("Socket UDP cerrado." );
}catch( UnknownHostException e ) {
System.out.println("Socket UDP cerrado." );
e.printStackTrace();
}catch( SocketException e ) {
System.out.println("Socket UDP cerrado." );
e.printStackTrace();
}catch( IOException e ) {
System.out.println("Socket UDP cerrado." );
e.printStackTrace();
}
}
}
// Constructor
ConexionEcho( Socket socket ) {
System.out.println( "Recibida una llamada en el puerto 7" );
this.socket = socket;
// Trabajamos por debajo de la prioridad de los otros puertos
setPriority( NORM_PRIORITY-1 );
// Se arranca el hilo y se pone a correr
start();
}
try {
// Conseguimos un canal de entrada desde el socket
entrada = new BufferedReader( new InputStreamReader(
socket.getInputStream() ) );
// Conseguimos un canal de salida hacia el socket. El canal es
// con liberación automática (autoflush)
salida = new PrintWriter( new OutputStreamWriter(
socket.getOutputStream()),true );
// Constructor
ConexionHttp( Socket socket ) {
System.out.println( "Recibida una llamada en el puerto 80" );
this.socket = socket;
// Trabajamos por debajo de la prioridad de los otros puertos
setPriority( NORM_PRIORITY-1 );
// Se arranca el hilo y se pone a correr
start();
}
83
... por lo que se remite al lector a él como referencia
Ahora llega el turno a la revisión de las partes más interesantes del ejemplo, que en este caso se
limitan a las líneas de código que se han incorporado nuevas al ejemplo java2009.java, para
implementar el servidor Eco a través de UDP. Cada uno de los servidores se implementan
mediante hilos de ejecución, así que los tres servidores actúan concurrente y asíncronamente en
diferentes hilos de ejecución. Además, siempre que un objeto servidor necesite proporcionar un
servicio a un cliente, lanzará otro hilo de ejecución a una prioridad más baja, para dar servicio a
ese cliente, siguiendo a la escucha de otros posibles clientes que requieran su atención.
Dejando a un lado la parte ya vista en el ejemplo base, el primer trozo de código en que hay que
detenerse es la implementación del servidor UDP.
Y, lo siguiente ya es el propio constructor de esa clase que se utiliza para instanciar el objeto que
va a proporcionar los servicios UDP de Eco a através del puerto 7. Este constructor, como se
muestra, se limita a invocar a su propio método start() para levantarse y empezar a correr. El
método start() invoca al método run().
// Constructor
ServidorEcoUdp() {
// Arrancamos el hilo e invocamos al método run() para que empiece
// a correr
start();
}
La siguiente línea de código muesta la instanciación del objeto DatagramSocket sobre el puerto
7, que ya se encuentra dentro de la acción del método run(), es decir, que es el comienzo el hilo
de ejecución.
Y ya, solamente queda el corazón del hilo de ejecución, que está formado por el bucle infinito
que instancia en primer lugar un objeto DatagramPacket vacío, para invocar al método
receive() sobre el DatagramSocket, pasándole el objeto DatagramPacket como parámetro.
Observe el lector que se ha limitado a 1024 byes los datos de entrada, por lo que no va a poder
recibir mensajes de longitud mayor que esa. Si es necesaria una longitud mayor, es suficiente con
adecuar el valor que se le pasa al constructor al que se necesite.
84
DatagramPacket paquete = new DatagramPacket( new byte[1024],1024 );
// Nos quedamos parados en el receive(), y devolvemos un socket
// cuando se recibe la llamada. Este socket es el que se pasa
// como parámetro al nuevo hilo de ejecución que se crea
socketDgrama.receive( paquete );
new ConexionEcoUdp( paquete );
}
El método receive() bloquea el hilo de ejecución y se queda a la espera de que llegue un paquete
datagrama. Cuando esto suceda, se rellenará el objeto DatagramPacket vacío, y se instanciará
un nuevo hilo de ejecución de tipo ConexionEcoUdp para atender la petición del cliente,
pasándole también como parámetro el objeto DatagramPacket, pero en este caso ya relleno con
los datos recibidos en el paquete enviado por el cliente.
Una vez satisfecho el requerimiento del cliente, el hilo de ejecución vuelve al inicio del bucle,
instanciando un nuevo objeto DatagramPacket vacío, y bloqueando el hilo de ejecución a la
espera de la llegada del siguiente paquete datagrama.
Ese objeto es guardado por el constructor para usarlo más tarde, a continuación fija la prioridad
por debajo del nivel de los hilos de ejecución que están monitorizando los puertos, de forma que
la actividad del hilo correspondiente a ConexionEchoUdp no interfiera con otros hilos de
ejecución que puedan lanzarse para atender a las peticiones recibidas por esos puertos. Y, por
fin, ya se invoca el método start(), que a su vez invoca al método run() y el hilo de ejecución se
pone en marcha. Todo esto es lo que se hace en el código que se muestra.
La misión encargada a este hilo de ejecución se limita al envío de una copia de los datos que le
llegan en el paquete recibido, de vuelta al cliente que se lo ha enviado. La dirección y puerto de
este cliente están incluidos en el paquete, donde el DatagramSocket del cliente los colocó antes
de enviar ese paquete.
El objeto DatagramPacket es casi directamente enviable de vuelta al cliente, pero para mostrar
el uso de algunos de los métodos de la clase DatagramPacket, se construye un nuevo objeto
para enviar de regreso al cliente, lo cual suele suceder más a menudo en servidores que realicen
tareas más complejas. El código siguiente es el que permite extraer la información necesaria para
generar un nuevo objeto. Como sugerencia al lector, podría intentar incluir la fecha en la parte de
85
datos del objeto, para que la información devuelta al cliente sea la misma que él envió, más la
fecha en que se recibió en el servidor; pero esto queda como ejercicio para el lector.
La parte del servidor HTTP se puede comprobar a través de un navegador indicando localhost
como nombre del servidor, y los otros servidores se pueden chequear mendiante el ejemplo
java2014.java, que ha sido pensado específicamente para probar los servidores Eco instalados en
la propia máquina en que se ejecuten cliente y servidor. El código completo del ejemplo es el
que se muestra a continuación.
Esta es una versión del ejemplo java2012 que accede al host local, es decir que solamente se ha
cambiado la definición del servidor para que quien responda al eco sea la misma máquina en que
se está ejecutando el programa. El resto del ejemplo es exactamente igual, y el lector puede
referirse a él para ampliar su información.
import java.net.*;
import java.io.*;
import java.util.*;
class java2014 {
public static void main( String[] args ) {
String servidor = "localhost"; // servidor local
int puerto = 7; // puerto eco
String cadTcp = "Prueba de Eco TCP";
String cadUdp = "Prueba de Eco UDP";
// Se cierra el socket
socketDgrama.close();
} catch( UnknownHostException e ) {
e.printStackTrace();
System.out.println(
"Debes estar conectado para que esto funcione bien." );
} catch( SocketException e ) {
e.printStackTrace();
} catch( IOException e ) {
e.printStackTrace();
}
}
}
87