los sockets en java

31
LOS SOCKETS EN JAVA A. 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. Fueron popularizados por Berckley Software Distribution, de la universidad norteamericana de Berkley. Los sockets han de ser capaces de utilizar el protocolo de streams TCP (Transfer Contro Protocol) y el de datagramas UDP (User Datagram Protocol). 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 primitivas se puede crear un sistema de diálogo muy completo.

Upload: alexis-patricio

Post on 22-Oct-2014

144 views

Category:

Documents


9 download

TRANSCRIPT

Page 1: Los Sockets en Java

LOS SOCKETS EN JAVA

A. 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.

Fueron popularizados por Berckley Software Distribution, de la universidad norteamericana de Berkley. Los sockets han de ser capaces de utilizar el protocolo de streams TCP (Transfer Contro Protocol) y el de datagramas UDP (User Datagram Protocol).

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 primitivas se puede crear un sistema de diálogo muy completo.

Imagen 10: Funcionamiento de una conexión socket

Page 2: Los Sockets en Java

Para más información véase [Rifflet, 1998].

B. Ejemplo de uso

Para comprender el funcionamiento de los sockets no hay nada mejor que estudiar un ejemplo. El que a continuación se presenta establece un pequeño diálogo entre un programa servidor y sus clientes, que intercambiarán cadenas de información.

a.) Programa Cliente

El programa cliente se conecta a un servidor indicando el nombre de la máquina y el número puerto (tipo de servicio que solicita) en el que el servidor está instalado.

Una vez conectado, lee una cadena del servidor y la escribe en la pantalla:

import java.io.*;

import java.net.*;

class Cliente {

static final String HOST = "localhost";

static final int PUERTO=5000;

public Cliente( ) {

try{

Socket skCliente = new Socket( HOST , Puerto );

Page 3: Los Sockets en Java

InputStream aux = skCliente.getInputStream();

DataInputStream flujo = new DataInputStream( aux );

System.out.println( flujo.readUTF() );

skCliente.close();

} catch( Exception e ) {

System.out.println( e.getMessage() );

}

}

public static void main( String[] arg ) {

new Cliente();

}

}

Page 4: Los Sockets en Java

En primer lugar se crea el socket denominado skCliente, al que se le especifican el nombre de host (HOST) y el número de puerto (PORT) en este ejemplo constantes.

Luego se asocia el flujo de datos de dicho socket (obtenido mediante getInputStream)), que es asociado a un flujo (flujo) DataInputStream de lectura secuencial. De dicho flujo capturamos una cadena ( readUTF() ), y la imprimimos por pantalla (System.out).

El socket se cierra, una vez finalizadas las operaciones, mediante el método close().

Debe observarse que se realiza una gestión de excepción para capturar los posibles fallos tanto de los flujos de datos como del socket.

b.) Programa Servidor

El programa servidor se instala en un puerto determinado, a la espera de conexiones, a las que tratará mediante un segundo socket.

Cada vez que se presenta un cliente, le saluda con una frase "Hola cliente N".

Este servidor sólo atenderá hasta tres clientes, y después finalizará su ejecución, pero es habitual utilizar bucles infinitos ( while(true) ) en los servidores, para que atiendan llamadas continuamente.

Tras atender cuatro clientes, el servidor deja de ofrecer su servicio:

import java.io.* ;

import java.net.* ;

class Servidor {

static final int PUERTO=5000;

public Servidor( ) {

try {

Page 5: Los Sockets en Java

ServerSocket skServidor = new ServerSocket( PUERTO );

System.out.println("Escucho el puerto " + PUERTO );

for ( int numCli = 0; numCli < 3; numCli++; ) {

Socket skCliente = skServidor.accept(); // Crea objeto

System.out.println("Sirvo al cliente " + numCli);

OutputStream aux = skCliente.getOutputStream();

DataOutputStream flujo= new DataOutputStream( aux );

flujo.writeUTF( "Hola cliente " + numCli );

skCliente.close();

}

System.out.println("Demasiados clientes por hoy");

Page 6: Los Sockets en Java

} catch( Exception e ) {

System.out.println( e.getMessage() );

}

}

public static void main( String[] arg ) {

new Servidor();

}

}

Utiliza un objeto de la clase ServerSocket (skServidor), que sirve para esperar las conexiones en un puerto determinado (PUERTO), y un objeto de la clase Socket (skCliente) que sirve para gestionar una conexión con cada cliente.

Mediante un bucle for y la variable numCli se restringe el número de clientes a tres, con lo que cada vez que en el puerto de este servidor aparezca un cliente, se atiende y se incrementa el contador.

Para atender a los clientes se utiliza la primitiva accept() de la clase ServerSocket, que es una rutina que crea un nuevo Socket (skCliente) para atender a un cliente que se ha conectado a ese servidor.

Se asocia al socket creado (skCliente) un flujo (flujo) de salida DataOutputStream de escritura secuencial, en el que se escribe el mensaje a enviar al cliente.

Page 7: Los Sockets en Java

El tratamiento de las excepciones es muy reducido en nuestro ejemplo, tan solo se captura e imprime el mensaje que incluye la excepción mediante getMessage().

c.) Ejecución

Aunque la ejecución de los sockets está diseñada para trabajar con ordenadores en red, en sistemas operativos multitarea (por ejemplo Windows y UNIX) se puede probar el correcto funcionamiento de un programa de sockets en una misma máquina.

Para ellos se ha de colocar el servidor en una ventana, obteniendo lo siguiente:

>java Servidor

Escucho el puerto 5000

En otra ventana se lanza varias veces el programa cliente, obteniendo:

>java Cliente

Hola cliente 1

>java cliente

Hola cliente 2

>java cliente

Hola cliente 3

>java cliente

connection refused: no further information

Mientras tanto en la ventana del servidor se ha impreso:

Sirvo al cliente 1

Sirvo al cliente 2

Sirvo al cliente 3

Demasiados clientes por hoy

Cuando se lanza el cuarto de cliente, el servidor ya ha cortado la conexión, con lo que se lanza una excepción.

Page 8: Los Sockets en Java

Obsérvese que tanto el cliente como el servidor pueden leer o escribir del socket. Los mecanismos de comunicación pueden ser refinados cambiando la implementación de los sockets, mediante la utilización de las clases abstractas que el paquete java.net provee.

Page 9: Los Sockets en Java

Lesson 1: Socket Communications

Lesson 1: Socket Communications

[ <<BACK] [ CONTENTS] [ NEXT>>]

Java Programming Language Basics, Part 1, finished with a simple network communications example using the Remote Method Invocation (RMI) application programming interface (API). The RMI example allows multiple client programs to communicate with the same server program without any explicit code to do this because the RMI API is built on sockets and threads.

This lesson presents a simple sockets-based program to introduce the concepts of sockets and multi-threaded programming. A multi-threaded program performs multiple tasks at one time such as fielding simultaneous requests from many client programs.

What are Sockets and Threads? About the Examples Example 1: Server-Side Program Example 1: Client-Side Program Example 2: Multithreaded Server Example More Information

Note: See Creating a Threaded Slide Show Applet for another example of how multiple threads can be used in a program.

What are Sockets and Threads?

A socket is a software endpoint that establishes bidirectional communication between a server program and one or more client programs. The socket associates the server program with a specific hardware port on the machine where it runs so any client program anywhere in the network with a socket associated with that same port can communicate with the server program.

A server program typically provides resources to a network of client programs. Client programs send requests to the server program, and the server program responds to the request.

Page 10: Los Sockets en Java

One way to handle requests from more than one client is to make the server program multi-threaded. A multi-threaded server creates a thread for each communication it accepts from a client. A thread is a sequence of instructions that run independently of the program and of any other threads.

Using threads, a multi-threaded server program can accept a connection from a client, start a thread for that communication, and continue listening for requests from other clients.

About the Examples

The examples for this lesson consist of two versions of the client and server program pair adapted from the FileIO.java application presented in Part 1, Lesson 6: File Access and Permissions.

Example 1 sets up a client and server communication between one server program and one client program. The server program is not multi-threaded and cannot handle requests from more than one client.

Example 2 converts the server program to a multi-threaded version so it can handle requests from more than one client.

Example 1: Client-Side Behavior

The client program presents a simple user interface and prompts for text input. When you click the Click Me button, the text is sent to the server program. The client program expects an echo from the server and prints the echo it receives on its standard output.

Example 1: Server-Side Behavior

The server program presents a simple user interface, and when you click the Click Me button, the text received from the client is displayed. The server echoes the text it receives whether or not you click the Click Me button.

Page 11: Los Sockets en Java

Example 1: Compile and Run

To run the example programs, start the server program first. If you do not, the client program cannot establish the socket connection. Here are the compiler and interpreter commands to compile and run the example.

javac SocketServer.java javac SocketClient.java

java SocketServer java SocketClient

Example 1: Server-Side Program

The server program establishes a socket connection on Port 4321 in its listenSocket method. It reads data sent to it and sends that same data back to the server in its actionPerformed method.

listenSocket Method

The listenSocket method creates a ServerSocket object with the port number on which the server program is going to listen for client communications. The port number must be an available port, which means the number cannot be reserved or already in use. For example, Unix systems reserve ports 1 through 1023 for administrative functions leaving port numbers greater than 1024 available for use.

public void listenSocket(){ try{ server = new ServerSocket(4321); } catch (IOException e) { System.out.println("Could not listen on port 4321"); System.exit(-1); }

listenSocketSocketserver.acceptSocket

try{

Page 12: Los Sockets en Java

client = server.accept(); } catch (IOException e) { System.out.println("Accept failed: 4321"); System.exit(-1); }

listenSocketBufferedReaderclientPrintWriter

try{ in = new BufferedReader(new InputStreamReader( client.getInputStream())); out = new PrintWriter(client.getOutputStream(), true); } catch (IOException e) { System.out.println("Read failed"); System.exit(-1); }}

listenSocket

while(true){ try{ line = in.readLine();//Send data back to client out.println(line); } catch (IOException e) { System.out.println("Read failed"); System.exit(-1); } }

actionPerformed Method

The actionPerformed method is called by the Java platform for action events such as button clicks. This actionPerformed method uses the text stored in the line object to initialize the textArea object so the retrieved text can be displayed to the end user.

public void actionPerformed(ActionEvent event) { Object source = event.getSource();

if(source == button){ textArea.setText(line); }}

Page 13: Los Sockets en Java

Example 1: Client-Side Program

The client program establishes a connection to the server program on a particular host and port number in its listenSocket method, and sends the data entered by the end user to the server program in its actionPerformed method. The actionPerformed method also receives the data back from the server and prints it to the command line.

listenSocket Method

The listenSocket method first creates a Socket object with the computer name ( kq6py) and port number (4321) where the server program is listening for client connection requests. Next, it creates a PrintWriter object to send data over the socket connection to the server program. It also creates a BufferedReader object to read the text sent by the server back to the client.

public void listenSocket(){//Create socket connection try{ socket = new Socket("kq6py", 4321); out = new PrintWriter(socket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader( socket.getInputStream())); } catch (UnknownHostException e) { System.out.println("Unknown host: kq6py"); System.exit(1); } catch (IOException e) { System.out.println("No I/O"); System.exit(1); }}

actionPerformed Method

The actionPerformed method is called by the Java platform for action events such as button clicks. This actionPerformed method code gets the text in the Textfield object and passes it to the PrintWriter object, which then sends it over the socket connection to the server program.

The actionPerformed method then makes the Textfield object blank so it is ready for more end user input. Lastly, it receives the text sent back to it by the server and prints the text out.

public void actionPerformed(ActionEvent event){ Object source = event.getSource();

Page 14: Los Sockets en Java

if(source == button){//Send data over socket String text = textField.getText(); out.println(text); textField.setText(new String("")); out.println(text); }//Receive text from server try{ String line = in.readLine(); System.out.println("Text received: " + line); } catch (IOException e){ System.out.println("Read failed"); System.exit(1); }}

Example 2: Multithreaded Server Example

The example in its current state works between the server program and one client program only. To allow multiple client connections, the server program has to be converted to a multithreaded server program.

First Client

Second Client

Third Client

In this example the listenSocket method loops on the server.accept call waiting for client connections and creates an instance of the ClientWorker class for each client

Page 15: Los Sockets en Java

connection it accepts. The textArea component that displays the text received from the client connection is passed to the ClientWorker instance with the accepted client connection.

public void listenSocket(){ try{ server = new ServerSocket(4444); } catch (IOException e) { System.out.println("Could not listen on port 4444"); System.exit(-1); } while(true){ ClientWorker w; try{//server.accept returns a client connection w = new ClientWorker(server.accept(), textArea); Thread t = new Thread(w); t.start(); } catch (IOException e) { System.out.println("Accept failed: 4444"); System.exit(-1); } }}

The important changes in this version of the server program over the non-threaded server program are the line and client variables are no longer instance variables of the server class, but are handled inside the ClientWorker class.

The ClientWorker class implements the Runnable interface, which has one method, run. The run method executes independently in each thread. If three clients request connections, three ClientWorker instances are created, a thread is started for each ClientWorker instance, and the run method executes for each thread.

In this example, the run method creates the input buffer and output writer, loops on the input stream waiting for input from the client, sends the data it receives back to the client, and sets the text in the text area.

class ClientWorker implements Runnable { private Socket client; private JTextArea textArea;

//Constructor ClientWorker(Socket client, JTextArea textArea) { this.client = client; this.textArea = textArea; }

Page 16: Los Sockets en Java

public void run(){ String line; BufferedReader in = null; PrintWriter out = null; try{ in = new BufferedReader(new InputStreamReader(client.getInputStream())); out = new PrintWriter(client.getOutputStream(), true); } catch (IOException e) { System.out.println("in or out failed"); System.exit(-1); }

while(true){ try{ line = in.readLine();//Send data back to client out.println(line);//Append data to text area textArea.append(line); }catch (IOException e) { System.out.println("Read failed"); System.exit(-1); } } }}

JTextArea.appendJTextArea.appendtextArea.append(line)synchronizedruntextArea.append(line)appendText(line) public synchronized void appendText(line){ textArea.append(line); }synchronizedtextAreatextArea

The finalize() method is called by the Java virtual machine (JVM)* before the program exits to give the program a chance to clean up and release resources. Multi-threaded programs should close all Files and Sockets they use before exiting so they do not face resource starvation. The call to server.close() in the finalize() method closes the Socket connection used by each thread in this program.

protected void finalize(){//Objects created in run method are finalized when//program terminates and thread exits try{ server.close(); } catch (IOException e) { System.out.println("Could not close socket"); System.exit(-1); }

Page 17: Los Sockets en Java

}

import java.awt.Color;

Page 18: Los Sockets en Java

import java.awt.BorderLayout;import java.awt.event.*;import javax.swing.*;

import java.io.*;import java.net.*;

class SocketClient extends JFrame implements ActionListener {

JLabel text, clicked; JButton button; JPanel panel; JTextField textField; Socket socket = null; PrintWriter out = null; BufferedReader in = null;

SocketClient(){ //Begin Constructor text = new JLabel("Text to send over socket:"); textField = new JTextField(20); button = new JButton("Click Me"); button.addActionListener(this);

panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.setBackground(Color.white); getContentPane().add(panel); panel.add("North", text); panel.add("Center", textField); panel.add("South", button); } //End Constructor

public void actionPerformed(ActionEvent event){ Object source = event.getSource();

if(source == button){//Send data over socket String text = textField.getText(); out.println(text);

textField.setText(new String(""));//Receive text from server try{

String line = in.readLine(); System.out.println("Text received :" + line); } catch (IOException e){

System.out.println("Read failed"); System.exit(1); } } } public void listenSocket(){//Create socket connection try{ socket = new Socket("kq6py", 4444); out = new PrintWriter(socket.getOutputStream(), true);

Page 19: Los Sockets en Java

in = new BufferedReader(new InputStreamReader(socket.getInputStream())); } catch (UnknownHostException e) { System.out.println("Unknown host: kq6py.eng"); System.exit(1); } catch (IOException e) { System.out.println("No I/O"); System.exit(1); } }

public static void main(String[] args){ SocketClient frame = new SocketClient();

frame.setTitle("Client Program"); WindowListener l = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } };

frame.addWindowListener(l); frame.pack(); frame.setVisible(true);

frame.listenSocket(); }}

Page 20: Los Sockets en Java

import java.awt.Color;import java.awt.BorderLayout;import java.awt.event.*;import javax.swing.*;

import java.io.*;import java.net.*;

class SocketClient extends JFrame implements ActionListener {

JLabel text, clicked; JButton button; JPanel panel; JTextField textField; Socket socket = null; PrintWriter out = null; BufferedReader in = null;

SocketClient(){ //Begin Constructor text = new JLabel("Text to send over socket:"); textField = new JTextField(20); button = new JButton("Click Me"); button.addActionListener(this);

panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.setBackground(Color.white); getContentPane().add(panel); panel.add("North", text); panel.add("Center", textField); panel.add("South", button); } //End Constructor

public void actionPerformed(ActionEvent event){ Object source = event.getSource();

if(source == button){//Send data over socket String text = textField.getText(); out.println(text);

textField.setText(new String(""));//Receive text from server try{

String line = in.readLine(); System.out.println("Text received :" + line); } catch (IOException e){

System.out.println("Read failed"); System.exit(1); } } } public void listenSocket(){//Create socket connection try{ socket = new Socket("kq6py", 4444);

Page 21: Los Sockets en Java

out = new PrintWriter(socket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(socket.getInputStream())); } catch (UnknownHostException e) { System.out.println("Unknown host: kq6py.eng"); System.exit(1); } catch (IOException e) { System.out.println("No I/O"); System.exit(1); } }

public static void main(String[] args){ SocketClient frame = new SocketClient();

frame.setTitle("Client Program"); WindowListener l = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } };

frame.addWindowListener(l); frame.pack(); frame.setVisible(true);

frame.listenSocket(); }}

Page 22: Los Sockets en Java

import java.awt.Color;import java.awt.BorderLayout;import java.awt.event.*;import javax.swing.*;

import java.io.*;import java.net.*;

class ClientWorker implements Runnable { private Socket client; private JTextArea textArea; ClientWorker(Socket client, JTextArea textArea) { this.client = client; this.textArea = textArea; }

public void run(){ String line; BufferedReader in = null; PrintWriter out = null; try{ in = new BufferedReader(new InputStreamReader(client.getInputStream())); out = new PrintWriter(client.getOutputStream(), true); } catch (IOException e) { System.out.println("in or out failed"); System.exit(-1); }

while(true){ try{ line = in.readLine();//Send data back to client out.println(line); textArea.append(line); } catch (IOException e) { System.out.println("Read failed"); System.exit(-1); } } }}

class SocketThrdServer extends JFrame{

JLabel label = new JLabel("Text received over socket:"); JPanel panel; JTextArea textArea = new JTextArea(); ServerSocket server = null;

SocketThrdServer(){ //Begin Constructor panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.setBackground(Color.white);

Page 23: Los Sockets en Java

getContentPane().add(panel); panel.add("North", label); panel.add("Center", textArea); } //End Constructor

public void listenSocket(){ try{ server = new ServerSocket(4444); } catch (IOException e) { System.out.println("Could not listen on port 4444"); System.exit(-1); } while(true){ ClientWorker w; try{ w = new ClientWorker(server.accept(), textArea); Thread t = new Thread(w); t.start(); } catch (IOException e) { System.out.println("Accept failed: 4444"); System.exit(-1); } } }

protected void finalize(){//Objects created in run method are finalized when //program terminates and thread exits try{ server.close(); } catch (IOException e) { System.out.println("Could not close socket"); System.exit(-1); } }

public static void main(String[] args){ SocketThrdServer frame = new SocketThrdServer();

frame.setTitle("Server Program"); WindowListener l = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; frame.addWindowListener(l); frame.pack(); frame.setVisible(true); frame.listenSocket(); }}

Page 24: Los Sockets en Java

Javachat: Idea del ProyectoLa implementación del programa servidor sigue las siguientes ideas:

1. Se inicia el servidor2. El servidor se mantiene escuchando cualquier petición de un cliente para conectarse.3. El servidor acepta al cliente.4. El servidor lanza un hilo de comunicación con el cliente.5. Por el hilo se envían y reciben mensajes a través del servidor entre todos los

clientes.6. Si el cliente cierra la comunicación el hilo se rompe y se corta la comunicación con

ese cliente.

La implementación del programa cliente sigue las siguientes ideas:

1. Se inicia el cliente2. El cliente lanza una petición al servidor para conectarse3. El servidor asigna un hilo al cliente al ser aceptado.4. El cliente envía y recibe mensajes por el hilo hacia todos o hacia algun usuario

específico, usando al servidor como puente para las comunicaciones.

Para esto se ha empleado objetos de la clase ServerSocket y Socket para el servidor y cliente respectivamente que permiten la conexion entre cliente y servidor mientras que los Hilos sirven para hacer que el servidor se mantenga escuchando y no interrumpa su proceso mientras los clientes se comunican a traves de mensajes.A continuacion unas definiciones:Sockets:Los sockets no son más que puntos o mecanismos de comunicación entre procesos que permiten que un proceso hable ( emita o reciba información ) con otro proceso incluso estando estos procesos en distintas máquinas. Esta característica de interconectividad entre máquinas hace que el concepto de socket nos sirva de gran utilidad.Hilos: Un hilo es un flujo de ejecución de código, y mediante hilos, podemos hacer que nuestros programas aparentemente realicen varias tareas al mismo tiempo.Por ejemplo, un código podría interaccionar con el usuario mientras realiza tareas de segundo plano de gran consumo de tiempo.Los hilos separados realmente no se ejecutan al mismo tiempo(a menos que se tenga una maquina multiprocesador); en realidad cada hilo obtiene secuencias de tiempo del mismo procesador.Ayuda para la aplicación: Siga los siguientes pasos:

1. Inicie el IDE Netbeans2. Abra el proyecto3. Ejecute la el archivo servidor.java4. Ejecute cuantas veces desee el archivo VentCliente.java5. Ingrese “localhost” si los clientes se ejecutan sobre una misma PC.6. Ingrese un nick, con el que sera identificado.7. En la ventana que le aparece Ud. podrá conversar con todos a la vez.8. Para conversar en privado con un solo contacto, elija en la lista de contactos a un

usuario y luego pulse el botón privado.

Page 25: Los Sockets en Java

9. A continuación le aparecerá una ventana mas pequeña en la que podrá comunicarse solo con su contacto.

10. Para salir simplemente cierre la ventana y el cliente se desconectará automáticamente.