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 positivastatic final int COMPLETADO = 2;
// respuesta final positivapublic 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)));
}
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();
} 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 IPfor(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 servidortry {
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 binarioSystem.out.println("type i");
CogeRespuesta(entradaPuertoControl);
// Respuesta del servidor}
// end if
salidaPuertoControl.println(comando);
// Envio del comando por el streamSystem.out.println(comando);
int result = CogeRespuesta(entradaPuertoControl);
// Obtiene la respuesta del servidor
if(result == PRELIMINAR){
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 NombreFicheroRandomAccessFile FicheroSalida = new RandomAccessFile(NombreFichero, "rw");
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 bufferSystem.out.print("#");
}
System.out.print("\n");
FicheroSalida.close();
} // end if SalvarAFichero
else
// Si no SalvarAFicherowhile((longitud = is.read(b)) != -1)
// Mientras existan datos en el bufferSystem.out.write(b, 0, longitud);
CogeRespuesta(entradaPuertoControl);
is.close();
Socketcliente.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// end if PRELIMINARelse {
// 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);
} 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 binarioSystem.out.println("type i");
CogeRespuesta(entradaPuertoControl);
// ok, envia el comando
salidaPuertoControl.println(comando);
System.out.println(comando);
int result = CogeRespuesta(entradaPuertoControl);
if(result == PRELIMINAR){
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 1KStringTokenizer 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 bufferSystem.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 positivaSystem.out.println("Error en la transferencia");
try {
Socketservidor.close();
} catch (IOException e) {
System.out.println("Error al cerrar el socket servidor.");
}
return(false);
}
}
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 trueelse if(entradaUsuario.startsWith("stor") || entradaUsuario.startsWith("stou"))
EnviarFichero(entradaUsuario, is, os);
else {
os.println(entradaUsuario);
// Se envia otro comando FTPCogeRespuesta(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