Esta clase implementa sockets TCP activos (capaces de recibir y transmitir datos).
Sus constructores son:
protected Socket () throws SocketException
protected Socket (SocketImpl impl) throws SocketException
public Socket (String host, int puerto) throws UnknownHostException, IOException
public Socket (InetAddress direccion, int puerto) throws IOException
public Socket (String host, int puerto, InetAddress dirLocal, intpuertoLocal) throws IOException
public Socket (InetAddress direccion, int puerto, InetAddress dirLocal, int puertolocal) throws IOException
public Socket (String host, int puerto, boolean flujo) throws IOException
public Socket (InetAddress host, int puerto, boolean flujo) throws IOException
El constructor public Socket (String host, int puerto) throws UnknownHostException, IOException es uno de los mas usados. Este metodo crea un objeto Socket y loconecta con el puerto con numero puerto de ordenador cuyo nombre es host. En el caso de que se haya instalado algun gestor de seguridad para la maquina virtual Java, se llama al metodo public void checkConnect(String host, int puerto, Object contexto) throws SecurityException, NullPointerException de la clase java.lang.SecurityManager para averiguar si la operacion esta permitida. Si no es asi, se lanza una excepcion java.lang.SecurityException. Si no se puede localizar el ordenador con nombre host, se lanza una excepcion java.net.UnknownException.
No hay que olvidar que el argumento puerto corresponde a la maquina de destino. Generalmente, los programadores no especifican el puerto local vinculado al socket, que es asignado por la maquina virtual Java: la MVJ pregunta al sistema operativo cual es el primer puerto libre y lo usa para el socket. De todos modos, hay dos constructores que permiten especificar el puerto local (puertoLocal). Si no estuviera libre, se lanzaria una excepcion.
Los metodos mas usados de esta clase son:
getInetAddress() :- Devuelve la direccion InetAddress a la cual esta conectado el socket
getPort() :- Devuelve la el numero de puerto al que esta conectado el socket
getLocalAddress() :- Devuelve la direccion local a la cual esta conectado el socket
getLocalPort() :- Devuelve el numero de puerto local al cual esta conectado el socket
getInputStream() :-Devuelve un flujo de entrada para el socket
getOutputStream() :-Devuelve un flujo de salida para el socket
close() :-Cierra el socket
El metodo public InetAddress getInetAddress() devuelve la direccion IP remota( en forma de un objeto InetAddress) a la que esta conectado el socket.
El metodo public int getPort() devuelve el puerto remoto al cual esta conectado el socket.
El metodo public InetAddress getLocalAddress() devuelve la direccion IP remota( en forma de un objeto InetAddress) a la que esta coenctado el socket.
El metodo public int getLocalPort() devuelve el puerto local al cual esta conectado el socket.
El metodo public void close() throws IOException cierra el socket y libera los recursos asociados. Si la operacion no es posible (por ejemplo, porque ya ha sido cerrado), se lanza una excepcion IOException. Al cerrar un socket, tambien se cierran los flujos de entrada y salida asociados.
El metodo public InputStream getInputStream() throws IOException devuelve un flujo de entrada para el socket. Con el, una aplicacion puede recibir informacion procedente de la maquina destino (es decir, del otro lado de la conexion)
El metodo public OutputStream getOutputStream() throws IOException devuelve un flujo de salidad para el socket, que puede usarse para enviar informacion a la maquina de destino (es decir, al otro lado de la conexion).
Para un socket activo, los dos ultimos metodos son imprescindibles: de algun modo debe el socket enviar y recibir datos a traves de la conexion TCP. El paquete java.net recurre al paquete java.io, en concreto a las clases java.io.InputStream y java.io.OutputStream. Estas dos clases tratan los datos como bytes y proporcionan metodos sencillos para leer y escribir bytes y arrays de bytes. Asimismo, sus subclases pueden "envolverse" en clases como java.io.Reader y java.io.Writer, que transmiten datos en forma de caracteres Unicode, no de bytes.
Cuando se trabaj con java.net hay tres clases de java.io que suelen usarse como envoltorio para los objetos devueltos por getOutputStream() y getIntputStrem
- BufferedReader. los dos metodos mas interesantes para nuestros propositos son read() y readLine(). El priemro devuelve el entero correspondiente al caracter leido ((0 -1 si se ha alcanzado el final del flujo); el segundo devuelve un String que corresponde a una linea de texto. Ambos provocan bloqueo: no terminan de ejecutarse hasta que haya datos disponibles o hasta que se lance una excepcion.
- PrintStream. Incluye los metodos print() y println() , que permiten enviar datos primitivos y objetos String. El metodo write() permite enviar bytes o arrays de bytes. Los tres metodos bloquean la E/S.
- PrintWriter. Es una clase similar a la anterios, e incluye tambien los metodos print() y println() . La principal diferencia es que permite enviar caracteres codificados mediante distintas codificaciones (ISO Latin, UTF-8...). Ambos bloquean la E/S.
Ejemplos:
//1 se crea un socket con el nombre del nodo y el numero de puerto 25
Socket socketCliente= new Socket("www.aidima.es", 25);
//2 Se crea un socket con la direccion IP dada y el puerto 25
Socket socketCliente= new Socket("26.56.78.140", 25);
//3 Se crea un socket con la direccion IP dada y el puerto 1025.
Socket socketCliente= new Socket("26.56.78.140", 1025);
//Se obtiene el nombre del ordenador al que pertenece el socket
System.out.println(SocketCliente.getInetAddress());
//Se obtiene el numero de puerto asociado al socket
System.out.println(socketCliente.getPort());
//Una vez establecida la conexion, se extraen los flujos de E/S asociados al socket
InputStream entrada = socketCliente.getInputStream();
OutputStream salida= socketCliente.getOutputStream();
//se lee del servidor un byte mediante el metodo read()
entrada.read();
//se envia al servidor un byte mediante el metodo write()
salida.write(64);
//se usa la clase PrintWriter como envoltorio de OutputStream para enviar una cadena de
//caracteres al flujo de salida. Luego, se cierrra el socket.
PrintWriter pw= new PrintWriter(salida,true);
pw.println("Escribiendo en la salida");
socketCliente.close();
//5 se crea un socket con la direccion IP dada y el puerto 25
Socket socketClietne= new Socket("26.56.78.140", 25);
//una vez establecida la conexion, se extraen los flujos de E/S asociados al socket
InputStream entrada = socketCliente.getInputStream();
OutputStream salida = socketCliente.getOutputStream();
//se usa la clase BufferedReader como envoltorio de InputStream para leer
//lineas completas del flujo de entrada
BufferedReader br= new BufferedReader(new InutStreamReader(SocketCliente.getInputStream()));
//se lee una linea completa y se cierra el socket
br.readLine();
socketCliente.close();
La implementacion de cualquier programa servidor en Java sigue esta secuencia de pasos:
- se crea objeto ServerSocket para escuchar a las peticiones que llegan al puerto asociado al servicio
- CUando se llama al metodo accetp(), el socket de servidor permanece a la espera de peticiones de clientes por el puerto.
- Al llegar una solicitud se siguen tres pasos:
3.1 Se acepta la conexion, lo cual genera un objeto Socket asociado al cliente
3.2 Se asocian objetos de las clases contenidas en el paquete java.io a los flujos(streams) de entrada y salida del socket.
3.3Se lee de los flujos y se escribe en ellos; es decir, se leen y procesas los mensajes entrantes y se envian las respuestas a los clientes.
- Se cierran los flujos
- Se cierra el socket vinculado al cliente
- El socket de servidor continua a la espera de nuevas peticiones
Igualmente los programas cliente se implementan asi:
- Se crea un objeto Socket, que tiene asociado un nodo de destino y un puerto donde se ejecuta el servicio de interes
- se asocian objetos de las clases cotnenidas en el paquete java.io a loas flujos (Streams) de entrada y salida del socket
- se lee de los flujos o se escribe en ellos
- se cierran los flujos
- se cierra el socket
El cierre de los sockets no debe pasarse por alto: por su naturaleza bidireccional consumen bastantes recursos, tanto de la maquina virtual Java como del sistema operativo.
Un socket se cierra cuando
- finaliza el programa que lo creo
- se llama a su metodo close()
- se cierra uno de los flujos de E/S asociados
- es eliminado por el recolector de basura
Nota: Si un socket no esta en uso pero permanece abierto no se podra utilizar el puerto local asociado. Una vez cerrado, el sistema operativo podra reutilizar el puerto para otr socket.