Sockets y Su Programación en Java
Sockets y Su Programación en Java
Trujillo – Perú
2007
Universidad Nacional de Trujillo Sockets y su programación en Java
Índice
Pág.
1. Fundamentos……………….………………………………………………………. 03
2. Definición………………………………………………………………………….. 03
______________________________________________________________________
2
Universidad Nacional de Trujillo Sockets y su programación en Java
Sockets
1. Fundamentos
Los sockets son un sistema de comunicación entre procesos de diferentes máquinas de una red.
Más exactamente, un socket es un punto de comunicación por el cual un proceso puede emitir o
recibir información.
Los sockets fueron desarrollados como un intento de generalizar el concepto de pipe (tubería
unidireccional para la comunicación entre procesos en el entorno Unix) en 4.2BSD bajo contrato
por DARPA (Defense Advanced Research Projects Agency). Sin embargo, fueron popularizados
por Berckley Software Distribution, de la Universidad Norteamericana de Berkley.
Los sockets utilizan una serie de primitivas para establecer el punto de comunicación, para
conectarse a una máquina remota en un determinado puerto que esté disponible, para escuchar
en él, para leer o escribir y publicar información en él, y finalmente para desconectarse. Con
todas las primitivas que ofrecen los sockets, se puede crear un sistema de diálogo muy
completo.
2. Definición
Un socket es un punto final de un proceso de comunicación. Es una abstracción que permite
manejar de una forma sencilla la comunicación entre procesos, aunque estos procesos se
encuentren en sistemas distintos, sin necesidad de conocer el funcionamiento de los protocolos
de comunicación subyacentes.
Es así como estos “puntos finales” sirven de enlaces de comunicaciones entre procesos. Los
procesos tratan a los sockets como descriptores de ficheros, de forma que se pueden
intercambiar datos con otros procesos transmitiendo y recibiendo a través de sockets.
______________________________________________________________________
3
Universidad Nacional de Trujillo Sockets y su programación en Java
Los mecanismos de comunicación entre procesos pueden tener lugar dentro de la misma
máquina o a través de una red. Generalmente son usados en forma de cliente-servidor, es decir,
cuando un cliente y un servidor establecen una conexión, lo hacen a través de un socket.
3. Modelos de Capas
Antes de continuar, conviene tener en mente una referencia acerca del modelo de capas de
redes para de esta manera tener un poco más clara el proceso de comunicación.
En la figura 3 se observa que un socket sirve de interfaz entre la capa de Aplicación y la capa de
Transporte en el modelo de capas usado en Internet.
4. Tipos de Sockets
El tipo de sockets describe la forma en la que se transfiere información a través de ese socket.
Existen muchos tipos de sockets, sin embargo, los más populares son:
• Stream (TCP)
• Datagram (UDP)
• Raw (acceso directo al protocolo: root)
Son un servicio orientado a la conexión, donde los datos se transfieren sin encuadrarlos en
registros o bloques, asegurándose de esta manera que los datos lleguen al destino en el orden de
______________________________________________________________________
4
Universidad Nacional de Trujillo Sockets y su programación en Java
transmisión. Si se rompe la conexión entre los procesos, éstos serán informados de tal suceso
para que tomen las medidas oportunas, por eso se dice que están libres de errores.
Son un servicio de transporte no orientado a la conexión. Son 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ó.
Las comunicaciones a través de datagramas usan UDP (User Datagram Protocol), lo que
significa que, 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, aunque tiene la ventaja de que se
pueden indicar direcciones globales y el mismo mensaje llegará a un muchas máquinas a la vez.
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.
El problema aparece al momento de decidir por cual protocolo o tipo de socket usar. La
decisión depende de la aplicación cliente/servidor que se esté desarrollando; aunque hay
algunas diferencias entre los protocolos que sirven para ayudar en la decisión y utilizar un
determinado tipo de socket.
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.
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.
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.
______________________________________________________________________
5
Universidad Nacional de Trujillo Sockets y su programación en Java
Los datagramas son bloques de información del tipo lanzar y olvidar, es decir, no hay la
seguridad de que el paquete llegue o no al destino. 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.
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 ficheros (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.
5. Modelo de Sockets
Como se ha mencionado, la comunicación con sockets hace uso de una serie de primitivas, entre
las que destacan socket para establecer el punto de comunicación, connect para conectarse a una
maquina remota en un determinado puerto que esté disponible, bind para escribir en él y
publicar información, read para leer de él, shutdown o close para desconectarse, entre otras que se
hacen mención en la tabla 1. Con todas estas primitivas se puede establecer un sistema de
comunicaciones muy completo. En la figura 5 se muestra el funcionamiento de una conexión
con sockets.
______________________________________________________________________
6
Universidad Nacional de Trujillo Sockets y su programación en Java
Tabla 1. Funciones para manipular los descriptores de archivos para conexiones remotas.
Normalmente, un servidor se ejecuta sobre una computadora específica y tiene un socket que
responde en un puerto específico. El servidor únicamente espera, escuchando a través del socket
a que un cliente haga una petición.
En el lado del cliente: el cliente conoce el nombre de host de la máquina en la cual el servidor se
encuentra ejecutando y el número de puerto en el cual el servidor está conectado. Para realizar
una petición de conexión, el cliente intenta encontrar al servidor en la máquina servidora en el
puerto especificado. Ver figura 6.
______________________________________________________________________
7
Universidad Nacional de Trujillo Sockets y su programación en Java
______________________________________________________________________
8
Universidad Nacional de Trujillo Sockets y su programación en Java
Si todo va bien, el servidor acepta la conexión. Además de aceptar, el servidor obtiene un nuevo
socket sobre un puerto diferente. Esto se debe a que necesita un nuevo socket (y, en consecuencia,
un número de puerto diferente) para seguir atendiendo al socket original para peticiones de
conexión mientras atiende las necesidades del cliente que se conectó. Ver figura 7.
Por la parte del cliente, si la conexión es aceptada, un socket se crea de forma satisfactoria y
puede usarlo para comunicarse con el servidor. Es importante darse cuenta que el socket en el
cliente no está utilizando el número de puerto usado para realizar la petición al servidor. En
lugar de éste, el cliente asigna un número de puerto local a la máquina en la cual está siendo
ejecutado. Ahora el cliente y el servidor pueden comunicarse escribiendo o leyendo en o desde
sus respectivos sockets.
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 cliente siempre inicia conexiones
con servidores y los servidores siempre están esperando que un cliente quiera establecer una
conexión. 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.
Y esto de asignar significado tiene una especial relevancia en el caso de la utilización de sockets.
En particular, como se ha dicho, entra entre las responsabilidades del programador la
implementación de un protocolo de comunicaciones que sea mutuamente aceptable entre las
dos máquinas a nivel de aplicación, para hacer que los datos fluyan de forma ordenada. 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 conexión e intercambiarse datos.
El paquete java.net de la plataforma Java proporciona una clase Socket, la cual implementa una
de las partes de la comunicación bidireccional entre un programa Java y otro programa en la
red.
______________________________________________________________________
9
Universidad Nacional de Trujillo Sockets y su programación en Java
De forma adicional, java.net incluye la clase ServerSocket, la cual implementa un socket el cual
los servidores pueden utilizar para escuchar y aceptar peticiones de conexión de clientes. Por
otra parte, si intentamos conectar a través de la Web, la clase URL y clases relacionadas
(URLConnection, URLEncoder) son probablemente más apropiadas que las clases de sockets.
Pero de hecho , las clases URL no son más que una conexión a un nivel más alto a la web y
utilizan como parte de su implementación interna a los sockets.
Socket miCliente;
______________________________________________________________________
10
Universidad Nacional de Trujillo Sockets y su programación en Java
En el ejemplo anterior no se usan excepciones; sin embargo, es una gran idea la captura de
excepciones cuando se está trabajando con sockets. El mismo ejemplo quedaría como:
Socket miCliente;
try {
miCliente = new Socket( "maquina",numeroPuerto );
}
catch( IOException e )
{
System.out.println( e );
}
Socket miServicio;
try {
miServicio = new ServerSocket( numeroPuerto );
}
catch( IOException e )
{
System.out.println( e );
}
______________________________________________________________________
11
Universidad Nacional de Trujillo Sockets y su programación en Java
DataInputStream entrada;
try {
entrada = new DataInputStream( miCliente.getInputStream() );
}
catch( IOException e )
{
System.out.println( e );
}
En el lado del Servidor, también usaremos DataInputStream, pero en este caso para recibir las
entradas que se produzcan de los clientes que se hayan conectado:
DataInputStream entrada;
try {
entrada = new DataInputStream( socketServicio.getInputStream() );
}
catch( IOException e )
{
System.out.println( e );
}
En la parte del Cliente podemos crear un stream de salida para enviar información al socket del
servidor utilizando las clases PrintStream o DataOutputStream:
PrintStream salida;
try {
salida = new PrintStream( miCliente.getOutputStream() );
}
catch( IOException e )
{
System.out.println( e );
}
La clase PrintStream tiene métodos para la representación textual de todos los datos primitivos
de Java. Sus métodos write y println() tienen una especial importancia en este aspecto. No
obstante, para el envío de información al servidor también podemos utilizar
DataOutputStream:
DataOutputStream salida;
try {
salida = new DataOutputStream( miCliente.getOutputStream() );
}
______________________________________________________________________
12
Universidad Nacional de Trujillo Sockets y su programación en Java
catch( IOException e )
{
System.out.println( e );
}
La clase DataOutputStream permite escribir cualquiera de los tipos primitivos de Java, muchos
de sus métodos escriben un tipo de dato primitivo en el stream de salida. De todos esos
métodos, el más útil quizás sea writeBytes().
En el lado del Servidor, podemos utilizar la clase PrintStream para enviar información al cliente:
PrintStream salida;
try {
salida = new PrintStream( socketServicio.getOutputStream() );
}
catch( IOException e )
{
System.out.println( e );
}
Siempre deberemos cerrar los canales de entrada y salida que se hayan abierto durante la
ejecución de la aplicación. En la parte del cliente:
try {
salida.close();
entrada.close();
miCliente.close();
}
catch( IOException e )
{
System.out.println( e );
}
try {
salida.close();
entrada.close();
socketServicio.close();
miServicio.close();
}
catch( IOException e )
{
System.out.println( e );
}
______________________________________________________________________
13
Universidad Nacional de Trujillo Sockets y su programación en Java
Es importante destacar que el orden de cierre es relevante. Es decir, se deben cerrar primero los
streams relacionados con un socket antes que el propio socket, ya que de esta forma evitamos
posibles errores de escrituras o lecturas sobre descriptores ya cerrados.
8. Aplicación Cliente-Servidor
Para entender de manera práctica los métodos descritos líneas arriba mostraremos una pequeña
aplicación cliente-servidor. Primero crearemos un servidor Server.java que atenderá a un cliente.
Para hacerlo simple, el servidor sólo le enviará un mensaje al cliente y éste terminará la
conexión. El servidor quedará disponible para atender a otro cliente. Es importante saber que,
para que el socket funcione, los servicios TCP/IP deben de estar activos, aunque los programas
cliente y servidor corran en la misma máquina.
A continuación escribiremos el código del servidor que “correrá para siempre”, así que para
detenerlo deberá de cortar manualmente la aplicación.
// servidor
import java.io.*;
import java.net.*;
Ahora vamos a crear la clase Cliente.java que representará al cliente que tan solo establece la
conexión, lee a través de un DataInputStream mediante el método readLine() lo que el servidor
le manda, lo muestra y lo corta.
// cliente:
import java.io.*;
import java.net.*;
______________________________________________________________________
14
Universidad Nacional de Trujillo Sockets y su programación en Java
Para probar esto, asegúrense que los servicios TCP/IP estén activos, ejecute Servidor.java en una
ventana y ejecute varias veces Cliente.java en otras ventanas. Las salidas serán mas o menos así:
Ventana servidor:
C:\java\curso>java Servidor
Llega el cliente 1
Llega el cliente 2
Llega el cliente 3
(----- cortar con control-C -----)
Ventana cliente:
C:\java\curso>java Cliente
Usted es mi cliente 1
C:\java\curso>java Cliente
Usted es mi cliente 2
C:\java\curso>java Cliente
Usted es mi cliente 3
(----- aquí cerramos el servidor -----)
Para entender con mayor claridad la aplicación de los sockets, a continuación se presenta el
código de un sistema cliente-servidor para la transmisión de archivos en cualquier formato.
El Servidor tiene la capacidad de transmitir a los clientes que lo deseen un determinado archivo,
por ejemplo trabajo.ppt, el cual se encuentra localizado en un path especifico que el Servidor
conoce. Entonces, uno o más clientes acceden a dicho servidor por medio de su dirección ip y
colocan el path local en el que desean almacenar el archivo que están solicitando al servidor. El
código de la aplicación descrita es el siguiente:
//Servidor.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
______________________________________________________________________
15
Universidad Nacional de Trujillo Sockets y su programación en Java
import java.net.*;
public Servidor()
{
frameServidor = new JFrame("Servidor de Archivos");
panelServidor = new JPanel();
lblNombreArchivo = new JLabel("Nombre del Archivo:");
txtNombreArchivo = new JTextField(40);
btnEscuchar = new JButton("Escuchar");
btnEscuchar.addActionListener(this);
JPanel panelNorte = new JPanel();
JPanel panelSur = new JPanel();
panelNorte.setLayout(new FlowLayout());
panelNorte.add(lblNombreArchivo);
panelNorte.add(txtNombreArchivo);
panelSur.setLayout(new FlowLayout());
panelSur.add(btnEscuchar);
panelServidor.setLayout(new BorderLayout());
panelServidor.add(panelNorte, BorderLayout.NORTH);
panelServidor.add(panelSur, BorderLayout.SOUTH);¡
frameServidor.getContentPane().add(panelServidor);
frameServidor.pack();
frameServidor.setVisible(true);
frameServidor.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
______________________________________________________________________
16
Universidad Nacional de Trujillo Sockets y su programación en Java
catch(Exception ex)
{
System.out.println(ex.getMessage());
}
//HiloSolicitud.java
import java.net.*;
import java.io.*;
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
}
}
//HiloTransferencia.java
import java.net.*;
import java.io.*;
______________________________________________________________________
17
Universidad Nacional de Trujillo Sockets y su programación en Java
String nombreArchivo;
//Cliente.java
import javax.swing.*;
import java.awt.*;
import java.net.*;
import java.awt.event.*;
public Cliente()
{
JPanel panelNorte = new JPanel();
JPanel panelCentro = new JPanel();
______________________________________________________________________
18
Universidad Nacional de Trujillo Sockets y su programación en Java
//HiloTransferenciaCliente.java
import java.net.*;
import java.io.*;
______________________________________________________________________
19
Universidad Nacional de Trujillo Sockets y su programación en Java
DataInputStream entrada;
String nomArchivo;
long tamArchivo;
Como se puede notar, tanto el cliente como el servidor hacen uso de Threads para un mejor
manejo de la transmisión del archivo, ya que el servidor envía el archivo por paquetes de un
determinado tamaño y el cliente se encarga de recibir cada uno de estos paquetes y formar
nuevamente el archivo para almacenarlo finalmente en el path destino.
______________________________________________________________________
20
Universidad Nacional de Trujillo Sockets y su programación en Java
10. Conclusiones
• Los sockets son mecanismos que permiten una comunicación sencilla entre procesos
remotos, otorgando distintos niveles de fiabilidad de acuerdo al tipo de socket que se
use, es decir, que dependiendo de la aplicación y del tipo de socket que se use en ella, la
comunicación siempre se realizará dentro de los parámetros predefinidos.
• El uso de sockets se ha extendido debido a que han sido diseñadas para servir en la
comunicación en el protocolo IP; resultando eficientes al momento de su aplicación.
• El uso de sockets en Java abstrae un conjunto de operaciones de bajo nivel que bajo
nivel, lo que resulta beneficioso para el programador que tan sólo se enfoca en la
aplicación y la manera en la que enviará y recibirá los distintos mensajes durante la
comunicación.
11. Referencias
______________________________________________________________________
21