Foros del Web » Programación para mayores de 30 ;) » C/C++ »

Problema con cliente FTP en C

Estas en el tema de Problema con cliente FTP en C en el foro de C/C++ en Foros del Web. Hola amigos, estoy picandome un cliente ftp en C desde 0, para subir archivos a un FTP server. Llevo el siguiente código de momento, he ...
  #1 (permalink)  
Antiguo 28/08/2013, 10:16
Avatar de jja
jja
 
Fecha de Ingreso: diciembre-2010
Ubicación: BCN
Mensajes: 47
Antigüedad: 13 años, 10 meses
Puntos: 0
Pregunta Problema con cliente FTP en C

Hola amigos, estoy picandome un cliente ftp en C desde 0, para subir archivos a un FTP server. Llevo el siguiente código de momento, he conseguido autenticarme en el servidor ftp, pero al enviar el fichero archivo.txt, me lo crea vacío en el servidor, y no lo sube y me sale en el servidor como archivo vacio de 0bytes.

Alguien sabria decirme en que estoy fallando?

Código C:
Ver original
  1. #pragma comment(lib, "wsock32.lib")
  2. #include <stdio.h>
  3. #include <windows.h>
  4. #include <Winsock.h>
  5.  
  6. WSADATA ws;
  7. char buf[10000];
  8. void output(char *str)
  9. {
  10.       FILE *fp = fopen("output.txt", "a+");
  11.       fprintf(fp, "%s\n", str);
  12.       fclose(fp);
  13. }
  14.  
  15. SOCKET ConnectFTP(char* ftpname, int port)
  16. {
  17.       WSAStartup(0x101, &ws);
  18.       // Open up a socket for out TCP/IP session
  19.       SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
  20.       // Set up socket information.
  21.       struct sockaddr_in a = {AF_INET, htons(port)};
  22.       // Get the ip address of our ftp
  23.       struct hostent *h = gethostbyname(ftpname);
  24.       a.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr *)h->h_addr)));
  25.       // Actually connect to the server
  26.       connect(s, (struct sockaddr *)&a, sizeof(a));
  27.       return s;
  28. }
  29.  
  30. void receiving(SOCKET s, char* string)
  31. {
  32.       char aa[1000] = {'/0'};
  33.       int ii = recv(s, aa, sizeof(aa), 0);
  34.       sprintf(buf, "~%s~", aa);
  35.       output(buf);
  36.       if(string !=0)
  37.             strcpy(string, aa);
  38. }
  39.  
  40. void sending(SOCKET s, char* verb)
  41. {
  42.       strcpy(buf, verb);
  43.       strcat(buf, "\r\n");
  44.       output("Sending: ");
  45.       output(buf);
  46.       send(s, buf, strlen(buf), 0);
  47. }
  48.  
  49. int _stdcall WinMain(HINSTANCE i, HINSTANCE j, char* k, int l)
  50. {
  51.       printf("Arrancando...\n");
  52.       SOCKET s1 = ConnectFTP("ftp.XXXXXXXXXXXXX.com", 21);
  53.       receiving(s1,0);
  54.       printf("Enviando usuario...\n");
  55.       sending(s1, "USER XXXXXX");
  56.       receiving(s1,0);
  57.       printf("Enviando contrasena...\n");
  58.       sending(s1, "PASS XXXYYYZZZ");
  59.       receiving(s1,0);
  60.       sending(s1, "CWD web");
  61.       sending(s1, "PASV");
  62.       char szString[1000];
  63.       receiving(s1, szString);
  64.       printf("Sending ...\n");
  65.       sending(s1, "STOR archivo.txt");
  66.       sending(s1, "QUIT");
  67.       receiving(s1,0);
  68.       return 0;
  69. }


El programa no me devuelve ningún error, a priori parece que funciona bien, aunque no sube el archivo, solo crea uno con el mismo nombre varcío

Gracias de antemano
__________________
El supremo arte de la guerra es someter al enemigo sin luchar.

Sun Tzu
  #2 (permalink)  
Antiguo 28/08/2013, 14:49
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 12 años, 3 meses
Puntos: 83
Respuesta: Problema con cliente FTP en C

Y donde está el envio de los datos del archivo?

Te lo comento de memoria y de hace tiempo, supongo que no la voy a cagar y el funcionamiento será parecido :)

Antes de entrar en modo pasivo (PASV) tienes que indicarle el tipo de transmision (TYPE, será en modo texto o en modo binario), luego pides entrar en modo pasivo y recoges lo que te responde: o te acepta en el mismo servidor o te pide que te conectes a otro; en cualquier caso te dará un numero de puerto que sera el que usaras para enviar el archivo. Lo siguiente es pedir el permiso para la subida (STOR), abrir un nuevo socket al mismo servidor (o al que te haya redirigido) por el puerto que te haya indicado, abres el archivo local para lectura y envias los datos.

Si no recuerdo mal esto deberia de funcionarte. Antes de nada comprueba lo que te retorna al entrar en modo pasivo, es probable que tengas que parsear los datos recibidos.

Saludos
vosk
  #3 (permalink)  
Antiguo 28/08/2013, 15:42
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 12 años, 3 meses
Puntos: 83
Respuesta: Problema con cliente FTP en C

Por cierto, deberias revisar si es necesario esperar otra respuesta despues del logeo:

envias user
lees estado
envias pass
lees estado
lees estado otra vez
comienzas a trabajar

Saludos
vosk
  #4 (permalink)  
Antiguo 28/08/2013, 16:03
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 12 años, 3 meses
Puntos: 83
Respuesta: Problema con cliente FTP en C

Vaya al final me pico la curiosidad :)

Al entrar en modo pasivo recibes una lista de numeros, que son una redireccion a una ip y un nº de puerto. La redireccion puede apuntar al mismo servidor o a otro, eso es lo de menos porque siempre tienes que parsear ese dato y usar el que te diga el servidor. Esto es lo que recibo en un test:

Código C:
Ver original
  1. Entering Passive Mode (127,0,0,1,207,22)

Parseo por comas los 4 primeros campos que son la redireccion (en este caso me dice que conecte a mi propio equipo por el loopback). Ahora me quedan los 2 campos finales que tambien los parseo y los convierto a enteros, de forma que tengo hp=207 y lp=22, con esto reconstruyo en numero de puerto pasivo en el que me estará esperando el servidor

Código C:
Ver original
  1. int puerto = (hp*256) + lp;

Te preguntaras: ¿eso para que? En el rfc tienes la descripcion de todo eso mas completa que lo que yo te pueda contar http://www.faqs.org/rfcs/rfc959.html Si no quieres leerlo tiene algo que ver en que todos los valores de ese resultado son representaciones textuales de enteros de 8 bits; el puerto está en 16 bits, luego haces esa operacion para crear un 16 bits a partir de los dos recibidos. Ojo, ese puerto que generas no esta en network byte order, es decir que cuando vas a crear el socket de trabajo tendras que usar el htons igualmente. Cuando se comenta esto suele decirse: me lo creo y paso a lo siguiente :)

Ahora solo te queda hacer una nueva conexion a la ip que recibes con ese puerto y empezar a subir.

Saludos
vosk
  #5 (permalink)  
Antiguo 29/08/2013, 10:17
Avatar de jja
jja
 
Fecha de Ingreso: diciembre-2010
Ubicación: BCN
Mensajes: 47
Antigüedad: 13 años, 10 meses
Puntos: 0
Respuesta: Problema con cliente FTP en C

Muchas gracias! Me queda más claro el tema

He leido la RFC y sino he entendido mal, que sigo un poco liado he visto que para enviar el fichero, en mi caso TYPE A porque es de texto, habria que usar APPE despues del comando STOR. Por lo que he añadido el siguiente codigo despues del STOR:

Código C:
Ver original
  1. char *ficheroA;
  2. FILE *pFichero;
  3.       char caracter;
  4.       pFichero=fopen("a.txt", "rb");
  5.       while (!feof(pFichero))
  6.       {
  7.           caracter = fgetc(pFichero);
  8.           sprintf(ficheroA,"%s%c",ficheroA,caracter);
  9.       }
  10.       fclose(pFichero);
  11.  
  12. char szString2[1000];
  13.       sprintf(szString2,"APPE %s", ficheroA);
  14.  
  15.       sending(s1, szString2);

Pero sigue sin enviarme el archivo :/ ¿Hay que enviar un ACK de cierre de envio de archivo?

Gracias!
__________________
El supremo arte de la guerra es someter al enemigo sin luchar.

Sun Tzu
  #6 (permalink)  
Antiguo 29/08/2013, 14:22
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 12 años, 3 meses
Puntos: 83
Respuesta: Problema con cliente FTP en C

Te conectas a la ip con el puerto que recibes como respuesta al entrar en modo pasivo?

El STOR crea y escribe un archivo, sobreescribe si ya existe; el APPE crea un archivo, añadi si ya existe. La transferencia de un archivo de texto puedes hacerla en modo binario sin problemas.

La idea es la siguiente: abres un socket de dialogo (sd), lo conectas al servidor, le dices que quieres trabajar en modo pasivo, te responde con una ip y un puerto, y ahora viene el truco: creas otro socket con esos datos, será el socket de transferencia (st). Le dices por 'sd' que quieres crear un archivo (STOR), esperas la respuesta por 'sd', le envias el archivo por 'st', esperas la respuesta por 'st', cierras 'st' y teoricamente ya lo tienes.

Otra cosa que no tiene nada que ver con ftp:

Código C:
Ver original
  1. char *ficheroA;
  2. FILE *pFichero;
  3. char caracter;
  4.  
  5. pFichero=fopen("a.txt", "rb");
  6. while (!feof(pFichero)) {
  7.     caracter = fgetc(pFichero);
  8.     sprintf(ficheroA, "%s%c", ficheroA, caracter);//ojo con esta linea
  9. }
  10. fclose(pFichero);

¿Que es *ficheroA y que cantidad y tamaño de datos puede albergar? Es un puntero, por lo que suele ocupar 4 bytes, y es de tipo char que pesa 1 byte, con lo que sin provocar ningun error puedes guardar 4 caracteres (incluido el \0 final, es decir "qwe\0") pero no deberias hacerlo asi, ni tampoco es necesario que envies todo el archivo en una sola linea. Tienes que usar un char bff[512] (p.ej.), leer sizeof(bff) del archivo y enviarlos en un buce hasta que hayas leido todo el archivo. Ten en cuenta que la transimision del archivo la estas haciendo a traves de un puerto en el que ya te está esperando, por eso a traves del socket que conectas a ese puerto solo tienes que enviar el archivo (ni append, ni otro verbo).

Una cosa mas importante que todo eso: parsea las respuestas que recibas, tienen un codigo de error (un numero) y una descripcion, suele ser el numero seguido de un guion seguido del texto. Tokenizas por el guion y ya tienes el numero (mejor dicho, tienes los codigos del ambito de trabajo, no es un numero en si sino una combinacion de codigos de ambito). Seguramente por ahi podras encontrar la descripcion de esos valores.

Saludos
vosk
  #7 (permalink)  
Antiguo 30/08/2013, 02:34
Avatar de jja
jja
 
Fecha de Ingreso: diciembre-2010
Ubicación: BCN
Mensajes: 47
Antigüedad: 13 años, 10 meses
Puntos: 0
Respuesta: Problema con cliente FTP en C

Buenas, muchas gracias por el esfuerzo, me estás ayudando mucho. He seguido al pie de la letra lo que me comentas, he parseado la respuesta de PASV, y he separado la IP que me devuelve el servidor, y he generado el puerto pasivo con hp y lp. Hasta aquí todo correcto. Pero cuando intento conectar un 2º socket a esta IP y PUERTO pasivo, no me responde. Te dejo el código que llevo por si tienes 5 minutos para probarlo. He marcado con una flecha en qué punto se me queda atrancado el programa porque el servidor no me da respuesta:

Código C:
Ver original
  1. #pragma comment(lib, "wsock32.lib")
  2. #include <stdio.h>
  3. #include <windows.h>
  4. #include <Winsock.h>
  5.  
  6. WSADATA ws;
  7. char buf[10000];
  8. char ficheroA[10000];
  9.  
  10. void output(char *str)
  11. {
  12.       FILE *fp = fopen("output.txt", "a+");
  13.       fprintf(fp, "%s\n", str);
  14.       fclose(fp);
  15. }
  16.  
  17. SOCKET Connect(char* ftpname, int port)
  18. {
  19.       WSAStartup(0x101, &ws);
  20.       // Open up a socket for out TCP/IP session
  21.       SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
  22.       // Set up socket information.
  23.       struct sockaddr_in a = {AF_INET, htons(port)};
  24.       // Get the ip address of our ftp
  25.       struct hostent *h = gethostbyname(ftpname);
  26.       a.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr *)h->h_addr)));
  27.       // Actually connect to the server
  28.       connect(s, (struct sockaddr *)&a, sizeof(a));
  29.       return s;
  30. }
  31.  
  32. void receiving(SOCKET s, char* string)
  33. {
  34.       char aa[1000] = {'/0'};
  35.       int ii = recv(s, aa, sizeof(aa), 0);
  36.       sprintf(buf, "~%s~", aa);
  37.       output(buf);
  38.       if(string !=0)
  39.             strcpy(string, aa);
  40. }
  41.  
  42. void sending(SOCKET s, char* verb)
  43. {
  44.       strcpy(buf, verb);
  45.       strcat(buf, "\r\n");
  46.       output("Sending: ");
  47.       output(buf);
  48.       send(s, buf, strlen(buf), 0);
  49. }
  50.  
  51. int _stdcall WinMain(HINSTANCE i, HINSTANCE j, char* k, int l)
  52. {
  53.       //Creacion de socket para conectar con FTP
  54.       SOCKET s1 = Connect("ftp.xxxxxxxxxxx.com", 21);
  55.       receiving(s1,0);
  56.  
  57.       //Envio de usuario
  58.       sending(s1, "USER yyyyyyyyyyyy");
  59.       receiving(s1,0);
  60.  
  61.       //Envio de contraseña
  62.       sending(s1, "PASS xxxxxxxxxxxxxx");
  63.       receiving(s1,0);
  64.  
  65.       //Envio de tipo de archivos que aceptará, en este caso binarios
  66.       sending(s1, "TYPE I");
  67.       receiving(s1, 0);
  68.  
  69.       char strPasv[1000];
  70.  
  71.       //Enviamos la activación del modo pasivo
  72.       sending(s1, "PASV");
  73.       receiving(s1, strPasv);
  74.       printf("%s\n",strPasv);
  75.  
  76.       //Parseamos para quedarnos exclusivamente con la IP y el puerto ********************************
  77.       //Ejemplo: "227 Entering Passive Mode (127,0,0,1,167,183)"
  78.       int cont=0;
  79.       int hostFound=0;
  80.       int salida=0;
  81.       char ipHost[24]="";
  82.       while((cont<sizeof(strPasv))&&(!salida))
  83.       {
  84.            if(strPasv[cont]=='(')
  85.            {
  86.                hostFound=1;
  87.            }
  88.            else if(strPasv[cont]==')')
  89.            {
  90.                salida=1;
  91.            }
  92.            else if(hostFound)
  93.            {
  94.                sprintf(ipHost,"%s%c",ipHost,strPasv[cont]);
  95.            }
  96.            cont++;
  97.       }
  98.  
  99.       char *trozos;
  100.  
  101.       //Separamos los trozos por las comas
  102.       trozos = strtok(ipHost,",");
  103.  
  104.       //Por cada trozo leido, la introduciremos en su correspondiente variable
  105.       char ipFTP2[16]="";
  106.       int hp=0;
  107.       int lp=0;
  108.       for(i=0;trozos;i++)
  109.       {
  110.             //Almacenamos cada trozo en la IP
  111.             if(i<16)
  112.             {
  113.                 if(i==0)
  114.                 {
  115.                     sprintf(ipFTP2,"%s%s",ipFTP2,trozos);
  116.                 }
  117.                 else
  118.                 {
  119.                     sprintf(ipFTP2,"%s.%s",ipFTP2,trozos);
  120.                 }
  121.             }
  122.             //Almacenamos el último trozo en el puerto
  123.             else if(i>=16)
  124.             {
  125.                 if(i==16)
  126.                 {
  127.                     hp=atoi(trozos);
  128.                 }
  129.                 else
  130.                 {
  131.                     lp=atoi(trozos);
  132.                 }
  133.  
  134.             }
  135.             trozos=strtok(0,",");
  136.       }
  137.       int portFTP2 = (hp*256) + lp;
  138.       printf("IP: %s - PASSIVE PORT: %d\n", ipFTP2, portFTP2);
  139.       //Fin del parseador ****************************************************************************
  140.  
  141.       //Creamos segundo socket para conectar a la IP y PUERTO brindados por el server para el envio
  142.       SOCKET s2 = Connect(ipFTP2, portFTP2);
  143.       receiving(s2,0);  //<==== AQUI NO LLEGA A RECIBIR LA CONTESTACION
  144.  
  145.       //Enviamos STOR para crear el fichero en el FTP y comenzar el envio por el socket s2
  146.       char strS1[1000];
  147.       sending(s1, "STOR c.txt");
  148.       receiving(s1, strS1);
  149.       printf("%s\n",strS1);
  150.  
  151.       //Envio por el segundo socket el contenido del archivo
  152.       sending(s2,"estoEsUnEjemploDeContenidoDeArchivo");
  153.       receiving(s2,0);
  154.      
  155.       //Cierro socket 2
  156.       sending(s2, "QUIT");
  157.  
  158.       //Cierro socket 1
  159.       sending(s1, "QUIT");
  160.       receiving(s1,0);
  161.       return 0;
  162. }

He quitado la parte del programa que parsea el fichero para simplificar, y envio por el momento ula cadena estoEsUnEjemploDeContenidoDeArchivo.

Seguramente que es una chorrada en lo que me falla, pero estoy atascado y ya no veo

1000 gracias
__________________
El supremo arte de la guerra es someter al enemigo sin luchar.

Sun Tzu
  #8 (permalink)  
Antiguo 30/08/2013, 02:54
Avatar de jja
jja
 
Fecha de Ingreso: diciembre-2010
Ubicación: BCN
Mensajes: 47
Antigüedad: 13 años, 10 meses
Puntos: 0
Respuesta: Problema con cliente FTP en C

El caso es que si intento conectarme a esa IP y PUERTO PASIVO por Telnet si que me conecta :/ :/ Que rayada
__________________
El supremo arte de la guerra es someter al enemigo sin luchar.

Sun Tzu
  #9 (permalink)  
Antiguo 30/08/2013, 03:42
Avatar de jja
jja
 
Fecha de Ingreso: diciembre-2010
Ubicación: BCN
Mensajes: 47
Antigüedad: 13 años, 10 meses
Puntos: 0
Respuesta: Problema con cliente FTP en C

A ver si se explicarte vosk lo que me está pasando.

Si no abro el socket s2, el programa queda esperando tras la instrucción STOR. En ese momento hago un telnet a mano desde un CMD con la IP y PUERTO pasivos devuelto por PASV, y entonces el programa lee perfectamente lo pasado por telnet y finaliza correctamente.

Creo que está habiendo un deathlock ya que el servidor está esperando pasarle la información por el socket, pero como a la vez está esperando en el STOR, pues no avanza... :/
__________________
El supremo arte de la guerra es someter al enemigo sin luchar.

Sun Tzu
  #10 (permalink)  
Antiguo 30/08/2013, 03:50
Avatar de jja
jja
 
Fecha de Ingreso: diciembre-2010
Ubicación: BCN
Mensajes: 47
Antigüedad: 13 años, 10 meses
Puntos: 0
Respuesta: Problema con cliente FTP en C

Ya lo he resuelto :) El problema era ese efectivamente, había que quitar los receiving(s1, strS1); y receiving(s2, strS1); de la creación del socket s2 y de debajo del STOR. Ya que se encontraban los sockets esperando en el servidor sin enviar respuesta.

Cuando tenga el código limpio lo cuelgo como agradecimiento para que la gente pueda descargarlo :)
__________________
El supremo arte de la guerra es someter al enemigo sin luchar.

Sun Tzu
  #11 (permalink)  
Antiguo 30/08/2013, 05:18
Avatar de jja
jja
 
Fecha de Ingreso: diciembre-2010
Ubicación: BCN
Mensajes: 47
Antigüedad: 13 años, 10 meses
Puntos: 0
Respuesta: Problema con cliente FTP en C

Al final lo tengo casi resuelto aunque me queda un problema. Si el fichero es pequeño y lo envío en un solo paquete todo va bien, pero si lo envío a trozos porque es más grande que el tamaño del buffer, no me llega el archivo entero al servidor, y además llega con símbolos raros . Los estoy leyendo correctamente, pero se pierden paquetes en el envío por lo que no debo estar enviando la información correctamente por el socket.

De hecho, he comprobado que solo llega "bien" el primer paquete, los siguientes llegan con símbolos raros:

Código C:
Ver original
  1. #pragma comment(lib, "wsock32.lib")
  2. #include <stdio.h>
  3. #include <windows.h>
  4. #include <Winsock.h>
  5.  
  6. WSADATA ws;
  7. char buf[10000];
  8.  
  9. void output(char *str)
  10. {
  11.       FILE *fp = fopen("output.txt", "a+");
  12.       fprintf(fp, "%s\n", str);
  13.       fclose(fp);
  14. }
  15.  
  16. SOCKET Connect(char* ftpname, int port)
  17. {
  18.       WSAStartup(0x101, &ws);
  19.       // Open up a socket for out TCP/IP session
  20.       SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
  21.       // Set up socket information.
  22.       struct sockaddr_in a = {AF_INET, htons(port)};
  23.       // Get the ip address of our ftp
  24.       struct hostent *h = gethostbyname(ftpname);
  25.       a.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr *)h->h_addr)));
  26.       // Actually connect to the server
  27.       connect(s, (struct sockaddr *)&a, sizeof(a));
  28.       return s;
  29. }
  30.  
  31. void receiving(SOCKET s, char* string)
  32. {
  33.       char aa[1000] = {'/0'};
  34.       int ii = recv(s, aa, sizeof(aa), 0);
  35.       sprintf(buf, "~%s~", aa);
  36.       output(buf);
  37.       if(string !=0)
  38.             strcpy(string, aa);
  39. }
  40.  
  41. void sending(SOCKET s, char* verb)
  42. {
  43.       strcpy(buf, verb);
  44.       strcat(buf, "\r\n");
  45.       output("Sending: ");
  46.       output(buf);
  47.       send(s, buf, strlen(buf), 0);
  48. }
  49.  
  50. int _stdcall WinMain(HINSTANCE i, HINSTANCE j, char* k, int l)
  51. {
  52.       //Creacion de socket para conectar con FTP
  53.       SOCKET s1 = Connect("ftp.xxxxxxxxxxxxxxx.com", 21);
  54.       receiving(s1,0);
  55.  
  56.       //Envio de usuario
  57.       sending(s1, "USER xxxxxxx");
  58.       receiving(s1,0);
  59.  
  60.       //Envio de contraseña
  61.       sending(s1, "PASS yyyyyyyyyy");
  62.       receiving(s1,0);
  63.  
  64.       //Envio de tipo de archivos que aceptará, en este caso binarios
  65.       sending(s1, "TYPE I");
  66.       receiving(s1, 0);
  67.  
  68.       char strPasv[1000];
  69.  
  70.       //Enviamos la activación del modo pasivo
  71.       sending(s1, "PASV");
  72.       receiving(s1, strPasv);
  73.       printf("%s\n",strPasv);
  74.  
  75.       //Parseamos para quedarnos exclusivamente con la IP y el puerto
  76.       int cont=0;
  77.       int hostFound=0;
  78.       int salida=0;
  79.       char ipHost[24]="";
  80.       while((cont<sizeof(strPasv))&&(!salida))
  81.       {
  82.            if(strPasv[cont]=='(')
  83.            {
  84.                hostFound=1;
  85.            }
  86.            else if(strPasv[cont]==')')
  87.            {
  88.                salida=1;
  89.            }
  90.            else if(hostFound)
  91.            {
  92.                sprintf(ipHost,"%s%c",ipHost,strPasv[cont]);
  93.            }
  94.            cont++;
  95.       }
  96.  
  97.       char *trozos;
  98.  
  99.       //Separamos los trozos por las comas
  100.       trozos = strtok(ipHost,",");
  101.  
  102.       //Por cada trozo leido, la introduciremos en su correspondiente variable
  103.       char ipFTP2[16]="";
  104.       int hp=0;
  105.       int lp=0;
  106.       for(i=0;trozos;i++)
  107.       {
  108.             //Almacenamos cada trozo en la IP
  109.             if(i<16)
  110.             {
  111.                 if(i==0)
  112.                 {
  113.                     sprintf(ipFTP2,"%s%s",ipFTP2,trozos);
  114.                 }
  115.                 else
  116.                 {
  117.                     sprintf(ipFTP2,"%s.%s",ipFTP2,trozos);
  118.                 }
  119.             }
  120.             //Almacenamos el último trozo en el puerto
  121.             else if(i>=16)
  122.             {
  123.                 if(i==16)
  124.                 {
  125.                     hp=atoi(trozos);
  126.                 }
  127.                 else
  128.                 {
  129.                     lp=atoi(trozos);
  130.                 }
  131.  
  132.             }
  133.             trozos=strtok(0,",");
  134.       }
  135.       int portFTP2 = (hp*256) + lp;
  136.       printf("IP: %s - PASSIVE PORT: %d\n", ipFTP2, portFTP2);
  137.       //Fin del parseador
  138.  
  139.       //Enviamos STOR para crear el fichero en el FTP y comenzar el envio por el socket s2
  140.       char strS1[1000];
  141.       sending(s1, "STOR c.txt");
  142.  
  143.       //Creamos segundo socket para conectar a la IP y PUERTO brindados por el server para el envio
  144.       SOCKET s2 = Connect(ipFTP2, portFTP2);
  145.  
  146.       //Lectura de archivo en modo binario
  147.       char buf1[512]="";
  148.       int total=0;
  149.       FILE *pFichero;
  150.       pFichero=fopen("c.txt", "rb");
  151.       while (!feof(pFichero))
  152.       {
  153.           int bytesR = fread (buf1, sizeof(char), sizeof(buf1), pFichero);
  154.           if( ferror( pFichero ) )      {
  155.              printf( "Read error\n" );
  156.              break;
  157.           }
  158.           total+=bytesR;
  159.           send(s2, buf1, strlen(buf1), 0);
  160.       }
  161.       fclose(pFichero);
  162.       printf("Total de bytes enviados: %d\n",total);
  163.  
  164.       //Cierro socket 2
  165.       sending(s2, "QUIT");
  166.  
  167.       //Cierro socket 1
  168.       sending(s1, "QUIT");
  169.       receiving(s1,0);
  170.       return 0;
  171. }

Hay que enviar algún tipo de flag o similar en los paquetes, o codificar en b64 durante el envío del contenido del archivo leído?

Graciass
__________________
El supremo arte de la guerra es someter al enemigo sin luchar.

Sun Tzu

Última edición por jja; 30/08/2013 a las 10:27
  #12 (permalink)  
Antiguo 30/08/2013, 15:33
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 12 años, 3 meses
Puntos: 83
Respuesta: Problema con cliente FTP en C

No lo he probado, pero te comento lo que creo que estoy viendo:

Código C:
Ver original
  1. int bytesR = fread (buf1, sizeof(char), sizeof(buf1), pFichero);
  2. ...
  3. send(s2, buf1, strlen(buf1), 0);

En sta linea estas leyendo 512 bloques (sizeof(buf1)) de 1 byte (sizeof(char)), es decir que le dices que te cargue 512 bytes en buf1; el problema es que el stream de lectura no se imagina que dos lineas despues vas a usar strlen(buf1) para saber la longitud de los datos y no te añade un nulo final, dicho de otra forma, strlen se basa en incrementar un contador desde el primer caracter puntero (buf1[0]) hasta que encuentre un final de cadena ('\0'), si lees 512 bytes y ninguno es un final de cadena el strlen te dará un resultado incorrecto. Prueba a hacer el send con:

Código C:
Ver original
  1. send(s2, buf1, bytesR, 0);

De esta forma te aseguras que envias el nº de datos leidos en el ciclo correspondiente, ademas te sirve no solo para enviar archivos de texto (nota que cuando quieras enviar una imagen no podras usar funciones de texto).

Saludos
vosk
  #13 (permalink)  
Antiguo 02/09/2013, 08:06
Avatar de jja
jja
 
Fecha de Ingreso: diciembre-2010
Ubicación: BCN
Mensajes: 47
Antigüedad: 13 años, 10 meses
Puntos: 0
Respuesta: Problema con cliente FTP en C

Muchas gracias de nuevo. Además del detalle que comentabas, que también me di cuenta, el fallo venía porque al enviar los archivos el FTP se saturaba y no recibía bien los paquetes. Tras poner un sleep(10) tras cada iteración del bucle que lee el archivo ya funciona correctamente.

Gracias Vosk, un saludo!
__________________
El supremo arte de la guerra es someter al enemigo sin luchar.

Sun Tzu
  #14 (permalink)  
Antiguo 12/09/2013, 11:14
Avatar de jja
jja
 
Fecha de Ingreso: diciembre-2010
Ubicación: BCN
Mensajes: 47
Antigüedad: 13 años, 10 meses
Puntos: 0
Respuesta: Problema con cliente FTP en C

Hola a todos, tras conseguir hacer funcionar mi cliente FTP contra un servidor FTP situado en un hosting de Internet, ahora estoy probando a conectar mi cliente con un servidor FTP motado en mi propio PC en local.

En este caso concreto, el programa se me queda en la instrucción "STOR", y me devuelve el siguiente código de error:

- 425 Can't open data connection

Como os digo, solo me pasa si el servidor FTP está en local. Si está en Internet funciona perfectamente.

He deshabilitado el firewall de Windows y el AV, y nada.

¿Se os ocurren otras posibles ideas?

Gracias!!
__________________
El supremo arte de la guerra es someter al enemigo sin luchar.

Sun Tzu
  #15 (permalink)  
Antiguo 15/09/2013, 03:02
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 12 años, 3 meses
Puntos: 83
Respuesta: Problema con cliente FTP en C

Siento no darte una solucion exacta pero te comento lo que he visto en una busqueda rapida: la mayoria de errores 425 en funcionamiento local se debe a la configuracion del servidor (personalmente nunca habia tenido este error, ni con la extension ftp de apache ni con el filezilla). Comprueba que el servidor en modo local no limite el 21 como unico puerto, en modo local puedes trabajar de forma activa sin problemas y por eso se limitan a abir solo el puerto ftp y esto provoca que la redireccion pasiva apunte a un puerto cerrado (o limitado).

Saludos
vosk

Etiquetas: cliente, ftp, funcion, int, programa, string, struct
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 15:36.