8. EJEMPLO APLICACIÓN CLIENTE FTP EN JAVA :

 

Aquí presentamos una aplicación cliente ftp desarrollada en lenguaje Java para la transmisión

de ficheros, que se ejecuta en modo texto .

 

Entre los comandos ftp más usuales destacan los siguientes :

 

Comandos :

Otros Comandos soportados , con la utilizacion de un puerto de datos :

 

 

 

8.1 Código Fuente en JAVA de la aplicación ejemplo Cliente FTP :

 

 

8.1.1 Métodos utilizados :

 

Método de clase que coge el texto de respuesta del servidor desde el puerto de control después de que se haya tecleado un comando ftp.

 

 

 

Método de clase que se encarga de preparar los comandos para enviar la orden port al servidor e indicarle en que puerto esta el cliente escuchando.

 

 

DataInputStream entradaPuertoControl PrintStream salidaPuertoControl)

Método de clase que implementa los comandos para la transferencia de ficheros que necesitan un puerto de datos. Le comunica al servidor el puerto de datos donde escuchará, después envia los comandos por el puerto de control y espera la respuesta del servidor por el puerto de datos.

 

 

 

entradaPuertoControl , PrintStream salidaPuertoControl)

Método de clase que se utiliza para subir al servidor un fichero en modo binario utilizando tanto stor

o bien stou.

 

 

(HazFtp.java)

 

import java.io.*;

import java.net.*;

import java.util.*; // Para maninpulación de Strings, ...

 

public class HazFtp {

// Primer dígito de los códigos de respuesta FTP

static final int PRELIMINAR = 1; // respuesta preliminar positiva

static final int COMPLETADO = 2; // respuesta final positiva

public static int CogeRespuesta(DataInputStream is) {

/* Coge el texto de respuesta del servidor desde el puerto de control despues que se haya

tecleado un comando ftp. Sabe la última linea de la respuesta porque empieza con 3

números y un espacio en blanco.

Parámetros :

- is input stream en el puerto de control ftp del socket - return devuelve el primer caracter de la ultima linea como un entero .*/

String salidaSocket;

try {

do {

salidaSocket = is.readLine( );

/* el método readLine , devuelve un string con el contenido de la linea que lee ,

y que reconoce por medio de los caracteres de control (\n ,\r ...) */

System.out.println(salidaSocket); // salida por pantalla

 

// Seguimos con el bucle do-while

} while (!(Character.isDigit(salidaSocket.charAt(0)) && Character.isDigit(salidaSocket.charAt(1)) && Character.isDigit(salidaSocket.charAt(2)) && salidaSocket.charAt(3) == ' '));

// Mientras ninguno de los 3 primeros digitos sea un blanco

} catch (IOException e) {

System.out.println("Error al intentar obtener la respuesta desde el puerto de control");

return(0);

}

return(Integer.parseInt(salidaSocket.substring(0, 1))); // Aquí es donde nos devuelve el primer digito

}

 

 

public static boolean port(ServerSocket Socketservidor, DataInputStream entradaPuertoControl, PrintStream salidaPuertoControl) {

/* Se encarga de preparar los comandos para enviar la orden port al servidor e indicarle

en que puerto esta el cliente escuchando, obteniendo una respuesta valida. */

Parámetros :

- Socketservidor : Socket para obtener la información. - entradaPuertoControl, salidaPuertoControl : Streams utilizados.*/

 

int localport = Socketservidor.getLocalPort( );

// Obtiene el puerto donde está escuchando el socket

System.out.println("Escucharemos en el puerto, " + localport);

InetAddress inetaddress = Socketservidor.getInetAddress();

/* Obtiene la dirección IP remota a la cual está conectado el socket */

InetAddress localip;

try {

localip = inetaddress.getLocalHost(); // Obtiene la IP local

} catch(UnknownHostException e) { System.out.println("No puedo obtener el local host");

return(false);

}

byte[] addrbytes = localip.getAddress( ); // Obtiene la dirección raw IP.

/* El resultado viene en orden de red, el byte de mayor orden de la dirección está

en getAddress[0]. Se declara un vector addrbytes y se le dice al servidor en

que puerto estamos escuchando */

short addrshorts[] = new short[4]; // donde almacenaremos la IP

for(int i = 0; i <= 3; i++){addrshorts[i] = addrbytes[i];

if(addrshorts[i] < 0) addrshorts[i] += 256;

}

// Los bytes mayores que 127 se entienden como números negativos

 

salidaPuertoControl.println("port " + addrshorts[0] + "," +addrshorts[1] + ","+

addrshorts[2] + ","+ addrshorts[3] + "," + ((localport & 0xff00) >>8) +

"," + (localport & 0x00ff));

System.out.println("port " + addrshorts[0] + "," +addrshorts[1] + ","+

addrshorts[2] + ","+ addrshorts[3] + "," + ((localport & 0xff00) >>8) +

"," + (localport & 0x00ff));

 

int result = CogeRespuesta(entradaPuertoControl); //Obtiene la respuesta del servidor.

return(result == COMPLETADO);

}

public static void PuertoDeDatos(String comando, boolean SalvarAFichero,

DataInputStream entradaPuertoControl PrintStream salidaPuertoControl) {

/* Implementa los comandos para la transferencia de ficheros que necesitan

un puerto de datos. Le comunica al servidor el puerto de datos donde escuchará,

después envia los comandos por el puerto de control y espera la respuesta del

servidor por el puerto de datos.

Parámetros :

- comando:list, nlist, o retr mas argumentos

- SalvarAFichero : Si se salva a fichero o se saca por pantalla.

- entradaPuertoControl: input stream en el puerto de control del socket

- salidaPuertoControl: output stream en el puerto de control del socket */

 

 

ServerSocket Socketservidor = null; // Declaramos un socket de servidor

try {

Socketservidor = new ServerSocket(0);

/* Se crea un socket servidor en cualquier puerto libre,

ya que le pasamos un 0 como parámetro port. */

} catch (IOException e) {

System.out.println(" No puedo obtener puerto para escuchar: " + Socketservidor.getLocalPort( ) + ", " + e);

return;

}

port(Socketservidor, entradaPuertoControl, salidaPuertoControl);

if(SalvarAFichero){

salidaPuertoControl.println("type i"); // Pasa el tipo de transferencia a binario

System.out.println("type i");

CogeRespuesta(entradaPuertoControl); // Respuesta del servidor

} // end if

salidaPuertoControl.println(comando); // Envio del comando por el stream

System.out.println(comando);

int result = CogeRespuesta(entradaPuertoControl); // Obtiene la respuesta del servidor

if(result == PRELIMINAR){ // Si se obtiene una respuesta positiva.

Socket Socketcliente = null;

try {

Socketcliente = Socketservidor.accept( );

/* al aceptar la conexión se crea un nuevo socket para procesarla.

El método accept() es bloqueante , el proceso esperará a que se

realice una conexión por parte del cliente. */

} catch (IOException e) {

System.out.println("Error en la conexión con el servidor (Accept) : " +

Socketservidor.getLocalPort() + ", " + e);

}

try {

InputStream is = Socketcliente.getInputStream();

/* declaramos un input stream para leer bytes desde el socket */

byte b[] = new byte[1024]; // Reservamos un buffer de 1K

int longitud; // Nos servirá para determinar el tamaño de los datos.

 

if(SalvarAFichero){

StringTokenizer stringtokens = new StringTokenizer(comando);

stringtokens.nextToken();

String NombreFichero = stringtokens.nextToken();// Obtiene el nombre de NombreFichero

RandomAccessFile FicheroSalida = new RandomAccessFile(NombreFichero, "rw");

// Abre el fichero para lectura / Escritura

 

while((longitud = is.read(b)) != -1){ // Mientras existan datos en el buffer

/* el método read(b) se encarga de leer bytes del stream

y almacenarlos en el vector b */

FicheroSalida.write(b, 0, longitud); // Escribe en el fichero el contenido del buffer

System.out.print("#");

}

System.out.print("\n");

FicheroSalida.close();

} // end if SalvarAFichero

 

else // Si no SalvarAFichero

while((longitud = is.read(b)) != -1) // Mientras existan datos en el buffer

System.out.write(b, 0, longitud);

CogeRespuesta(entradaPuertoControl);

is.close();

Socketcliente.close();

} catch (IOException e) {

e.printStackTrace();

}

} // end if PRELIMINAR

else { // Si la respuesta no es positiva

System.out.println("Se ha producido un error en la transferencia");

try {

Socketservidor.close();

} catch (IOException e) {

System.out.println("Se ha producido un error al cerrar el socket servidor.");

}

}

}

public static boolean EnviarFichero(String comando, DataInputStream

entradaPuertoControl, PrintStream salidaPuertoControl){

/*. Subir al servidor un fichero en modo binario utilizando tanto stor o bien stou.

Parámetros :

- comando : stor o stou mas argumentos

- entradaPuertoControl : input stream en el puerto de control

- salidaPuertoControl : output stream en el puerto de control. */

ServerSocket Socketservidor = null;

try {

Socketservidor = new ServerSocket(0); // Se crea un socket servidor en cualquier puerto libre.

} catch (IOException e) {

System.out.println("No puedo obtener puerto para escuchar : " +

Socketservidor.getLocalPort() + ", " + e);

return(false);

}

 

port(Socketservidor, entradaPuertoControl, salidaPuertoControl);

salidaPuertoControl.println("type i"); // Pone el tipo de transferencia a binario

System.out.println("type i");

CogeRespuesta(entradaPuertoControl);

 

// ok, envia el comando

salidaPuertoControl.println(comando);

System.out.println(comando);

int result = CogeRespuesta(entradaPuertoControl);

 

 

if(result == PRELIMINAR){

// Escucha en el puerto de datos

Socket Socketcliente = null;

try {

Socketcliente = Socketservidor.accept();

/* Acepta la llegada de la conexión y crea un socket para procesarla */

} catch (IOException e) {

System.out.println("El Servidor no acepta la conexión (Accept): " +

Socketservidor.getLocalPort() + ", " + e);

}

try {

OutputStream SalidaPuertoDatos = Socketcliente.getOutputStream();

byte b[] = new byte[1024]; // Creamos un buffer de 1K

StringTokenizer stringtokens = new StringTokenizer(comando);

stringtokens.nextToken();

String NombreFichero = stringtokens.nextToken(); // toma el nombre del fichero

// abre el fichero para lectura

RandomAccessFile FicheroEntrada = new RandomAccessFile(NombreFichero, "r");

 

// Envia el fichero

int longitud;

while ((longitud = FicheroEntrada.read(b)) > 0) {

/* El método read lee bytes del fichero y los almacena en el buffer.

Este método devolverá un 0 al final del fichero */

SalidaPuertoDatos.write(b, 0, longitud); // Escribe en el stream el contenido del buffer

System.out.print("#");

} // end while

 

System.out.print("\n");

FicheroEntrada.close();

SalidaPuertoDatos.close();

Socketcliente.close();

Socketservidor.close();

result = CogeRespuesta(entradaPuertoControl); // Obtiene la respuesta del servidor

} catch (IOException e) {

e.printStackTrace();

}

return(result == COMPLETADO);

} // end if PRELIMINAR

 

 

else { // Si no es positiva

System.out.println("Error en la transferencia");

try {

Socketservidor.close();

} catch (IOException e) {

System.out.println("Error al cerrar el socket servidor.");

}

return(false);

}

 

} // end EnviarFichero

 

 

 

 

 

 

 

 

public static void main(String[] args) {

 

/* Bucle principal que clasifica los comandos y los envia a la función apropiada.

Parámetros : - args : args[0] es el nombre del host para hacer ftp.*/

if(args.length != 1) {

System.out.println("Uso de la aplicacion : java HazFtp maquina servidor FTP");

System.exit(1); // salimos de la aplicación

}

Socket miSocket = null;

PrintStream os = null;

DataInputStream is = null;

// Declaramos el socket y los streams a utilizar

DataInputStream stdIn = new DataInputStream(System.in);

// Instanciamos un stream para leer desde la entrada estandar

try {

miSocket = new Socket(args[0], 21);

/* Creamos el socket pasandole como parámetros el host (IP o String host)

y el puerto bien conocido del servicio ftp (21). */

os = new PrintStream(miSocket.getOutputStream());

is = new DataInputStream(miSocket.getInputStream());

} catch (UnknownHostException e) {

System.err.println("Host Desconocido : "+args[0]);

} catch (IOException e) {

System.err.println("No se puede abrir una conexión con el host: " +args[0]);

}

 

 

 

if (miSocket != null && os != null && is != null) {

try {

String entradaUsuario;

CogeRespuesta(is); //Obtiene la respuesta del servidor

// Bucle de lectura y escritura

while ((entradaUsuario = stdIn.readLine()) != null) {

if(entradaUsuario.startsWith("list") || entradaUsuario.startsWith("nlst"))

PuertoDeDatos(entradaUsuario, false, is, os);

else if(entradaUsuario.startsWith("retr"))

PuertoDeDatos(entradaUsuario, true, is, os); // SalvarAFichero a true

else if(entradaUsuario.startsWith("stor") || entradaUsuario.startsWith("stou"))

EnviarFichero(entradaUsuario, is, os);

else {

os.println(entradaUsuario); // Se envia otro comando FTP

CogeRespuesta(is); //Obtiene la respuesta del servidor

} // end else

} // end while entradaUsuario

os.close();

is.close();

miSocket.close(); //Cerramos los streams y el socket

 

} catch (IOException e) {

System.err.println("E/S fallo en la conexión a : "+ args[0]);

}

} // if miSocket

} // main

} // Class HazFtp