Visualizzazione dei risultati da 1 a 8 su 8
  1. #1
    Utente di HTML.it
    Registrato dal
    Apr 2005
    Messaggi
    38

    [C++] Socket, client ftp

    Salve a tutti!

    Nel procedere con lo studio delle socket windows ho voluto creare un programma client FTP per mettere alla prova ciò che avevo studiato.
    Mi sono informato anche sul funzionamento dello scambio di informazioni fra client e server ftp e se ho capito bene:

    Il server FTP è in ascolto sulla porta 21.
    Il client si connette a tale porta per inviare e ricevere rispettivamente comandi e risposte.

    Per il trasferimento di dati per i file invece è necessaria una seconda connessione che può essere in due modalità:

    - attiva: (il client apre una porta locale (>1023) e la notifica al server tramite la connessione principale(comandi) e attende il server, a connessione stabilita il server esegue il binding sulla porta 20);
    - passiva: (il server notifica al client la porta remota (>1023) comunicandola nel canale comandi in modo tale che il client possa aprire la connessione su tale porta).

    Procedendo a piccoli passi ho iniziato il programma in questo modo:
    codice:
    #include <iostream>
    #include <winsock2.h>
    
    int initWsaData(int a, int b);                             //Init WSADATA
    int initSK(int af, int type, int proto);                   //Init socket
    int cnSK(int af, const char *ip, u_short port, SOCKET s);  //Apri connessione socket
    int getSvMex(SOCKET s);                                    //Riceve e controlla la ricezione cmd
    int sendClMex(SOCKET s);                                   //invia e controlla il risultato dell'invio cmd
    
    int main() {
    
    	UINT_PTR sk; //socket
    	
    	std::cout << "***************************\n";
    	if(initWsaData(2,2) != NO_ERROR) {
    		std::cerr << "* WSADATA:         ERRORE *\n";
    		return (1);
    	} else {
    		std::cout << "* WSADATA:         Ok     *\n";
    	}
    
    	sk = initSK(2,1,6);// AF_INET SOCK_STREAM IPPROTO_TCP
    	if(sk == INVALID_SOCKET){
    		std::cerr << "* SOCKET:          ERRORE *\n";
    		WSACleanup();
    		return (2);
    	} else {
    		std::cout << "* SOCKET:          OK     *\n";
    	}
    
    	if(cnSK(2,"INDIRIZZO_IP",21,sk) == SOCKET_ERROR) {
    		WSACleanup();
    		closesocket(sk);
    		std::cerr << "* CONNESSIONE:     ERRORE *\n";
    		return (3);
    	} else {
    		std::cout << "* CONNESSIONE:     ATTIVA *\n";
    	}
    	std::cout << "***************************\n";
    
    	if(getSvMex(sk) <=0) {
    		std::cerr << "ERRORE!\n";
    		WSACleanup();
    		closesocket(sk);
    		return (4);
    	}
    
    	while(true) {
    		if(sendClMex(sk)<= 0) break;
    		if(getSvMex(sk) <= 0) break;
    	}
    	
    	WSACleanup();
    	closesocket(sk);
    	return (0);
    }
    int initWsaData(int a, int b) {
    	WSADATA wsaData;
    	int res;
    	res = WSAStartup(MAKEWORD(a, b), &wsaData);
    	return (res);
    }
    int initSK(int af, int type, int proto) {
    	UINT_PTR res;
    	res = socket(af, type, proto);
    	return (res);
    }
    int cnSK(int af, const char *ip, u_short port, SOCKET s) {
    	int res;
    	sockaddr_in addr;
    	addr.sin_family = af;
    	addr.sin_addr.s_addr = inet_addr(ip);
    	addr.sin_port = htons(port);
    
    	res = connect(s, (SOCKADDR*)&addr, sizeof(addr));
    	return (res);
    }
    int getSvMex(SOCKET s) {
    	char buf[256];
    	int by = 0;
    
    	std::cout << "Attesa risposta: ";
    	by = recv(s, buf, (int)strlen(buf), NULL);
    	if(by < 0) {
    		std::cout << "NESSUNA RISPOSTA!\n";
    		return (0);
    	}
    
    	if(by > 0) std::cout << buf;
    
    	std::cout << std::endl;
    	return (by);
    }
    int sendClMex(SOCKET s) {
    	char buf[256];
    	int by = 0;
    
    	std::cin.getline(buf, (int)strlen(buf));
    	by = send(s, buf, sizeof(buf), NULL);
    
    	if(by < 0) {
    		std::cerr << "\t\tErrore invio: " << buf << '\n';
    		return (by);
    	}
    
    	std::cout << "Inviato cmd    : " << buf << '\n';
    	return (by);
    }
    Questo è l'output del programma:
    codice:
    **************************
    * WSADATA:        OK     *
    * SOCKET:         OK     *
    * CONESSIONE:     ATTIVA *
    **************************
    Attesa risposta: 220 XXXX Ftp Server (e a capo una sorta di simboli inconprensibili)
    Poi rimane in attesa del cmd e ad esmpio scrivo USER xxxxxxxxx il server dopo pochi secondi mi risponde con:
    codice:
    Attesa risposta: 421 Connection Closed, Timed Out. (e i simboli incomprensibili)
    Il fatto che riesco a ricevere le risposte del server mi fà pensare che non ho proprio fatto una "schifezza"... ma allora quale/i possono essere i motivi per cui qualsiasi cmd che invio io non funzionano e sempre e comunque il server mi risponde con... lo steso messaggio di errore temporaneo ? Grazie a tutti quelli che risponderanno.

  2. #2
    Utente di HTML.it L'avatar di XWolverineX
    Registrato dal
    Aug 2005
    residenza
    Prague
    Messaggi
    2,563
    Ti conisglio di inserire delle chiamate a cout di debug per verificare preventivamente le stringhe che gli stai inviando.
    "Se proprio devono piratare, almeno piratino il nostro." (Bill Gates)

    "Non è possibile che 2 istituzioni statali mi mettano esami nello stesso giorno." (XWolverineX)

    http://xvincentx.netsons.org/programBlog

  3. #3
    Utente di HTML.it
    Registrato dal
    Apr 2005
    Messaggi
    38
    Ciao ,

    Nell'ultima funzione 'sendClMex()' (nome originalissimo ), subito dopo l'invio, controllo il valore di ritorno di 'send()' e se maggiore di '0' raccoglie tramite 'std::cin.getline(buf, 256)' nella variabile 'char buf[256]' appunto e lo stampa... ed è ciò che io effettivamente inserisco... quindi al server FTP "in teoria" dovrebbe arrivare la stringa nel formato corretto ad esempio:

    se digito: USER idUtente
    il programma raccoglie la stringa, la invia e se ok la stampa, ed è identica!!

    Se ho capito bene, altrimenti chiedo scusa , ma non saprei stampare dunque raccogliere il valore che la send() invia in altro modo. Sinceramente non capisco perchè la 'recv()' raccoglie il messaggio correttamente ma popola il resto dell'array di chars con simboli che non hanno nulla a che fare col messaggio. Sapete come evitare questo comportamento ?
    Grazie.

  4. #4
    Utente di HTML.it L'avatar di XWolverineX
    Registrato dal
    Aug 2005
    residenza
    Prague
    Messaggi
    2,563
    recv restituisce il numero di bytes ricevuti. Quindi devi usare quel valore come limite di lettura dal buffer che ti arriva, e non andare oltre. Al carattere bytesrecv + 1, piazzaci 0 per terminare la stringa, e poi la stampi
    "Se proprio devono piratare, almeno piratino il nostro." (Bill Gates)

    "Non è possibile che 2 istituzioni statali mi mettano esami nello stesso giorno." (XWolverineX)

    http://xvincentx.netsons.org/programBlog

  5. #5
    Utente di HTML.it
    Registrato dal
    Apr 2005
    Messaggi
    38
    Ciao,
    scusa se rispondo in ritardo.
    Perfetto grazie al tuo consiglio ora stampo solo ciò che serve senza più inutili caratteri.
    Mentre invece non riesco ancora a capire come mai non ricevo le risposte del server remoto, a parte il messaggio di benvenuto e quello di connessione scaduta, quelli arrivano sempre!)
    Ho fatto queste prove:
    - Tramite telnet mi sono connesso al server ftp e funzia tutto bene.
    - Ho allora creato un nuovo progetto da visual studio 2008 e ho creato un mini server l'ho messo in ascolto sulla porta 3636 e mi ci sono connesso tramite telnet e mi sono accorto che telnet invia i comandi al server carattere per carattere poiché in principio digitando un carattere in telnet, il mio "server" riceveva il carattere e terminava, giustamente perché lo avevo strutturato in modo da ricevere una stringa e poi terminare. In seguito nel "server" fatto in casa ho inserito un ciclo do while(); finchè il carattere ricevuto non fosse un carattere di fine riga.
    - Ho modificato allora il "client" fatto in casa in modo che trasmettesse al server remoto carattere per carattere ma... di nuovo ricevo il messaggio di benvenuto e quello di connessione scaduta.
    A questo punto non so che altro provare... dove sto sbagliando ?
    Grazie ancora per le risposte.

  6. #6
    Utente di HTML.it L'avatar di XWolverineX
    Registrato dal
    Aug 2005
    residenza
    Prague
    Messaggi
    2,563
    Se posti il codice completo (con la modifica suggerita sopra) lo proverò sui miei server.
    "Se proprio devono piratare, almeno piratino il nostro." (Bill Gates)

    "Non è possibile che 2 istituzioni statali mi mettano esami nello stesso giorno." (XWolverineX)

    http://xvincentx.netsons.org/programBlog

  7. #7
    Utente di HTML.it
    Registrato dal
    Apr 2005
    Messaggi
    38
    Ciao, questo è il codice completo sul quale sto studiando, perdona la poca esperienza:

    codice:
    #include <iostream>
    #include <winsock2.h>
    
    int initWsaData(int a, int b);                             //Init WSADATA
    int initSK(int af, int type, int proto);                   //Init socket
    
    int cnSK(int af, const char *ip, u_short port, SOCKET s);  //Apri connessione socket
    
    int getSvMex(SOCKET s);                                    //Riceve e controlla la ricezione cmd
    int sendClMex(SOCKET s);                                   //invia e controlla il risultato dell'invio cmd
    void displayBuf(char buf[], int len);                      //Stampa le risposte del server eliminando i simboli inutili
    
    int main() {
    
    	UINT_PTR sk; //socket
    	
    	std::cout << "***************************\n";
    	if(initWsaData(2,2) != NO_ERROR) {
    		std::cerr << "* WSADATA:         ERRORE *\n";
    		return (1);
    	} else {
    		std::cout << "* WSADATA:         Ok     *\n";
    	}
    
    	sk = initSK(2,1,6);// AF_INET SOCK_STREAM IPPROTO_TCP
    	if(sk == INVALID_SOCKET){
    		std::cerr << "* SOCKET:          ERRORE *\n";
    		WSACleanup();
    		return (2);
    	} else {
    		std::cout << "* SOCKET:          OK     *\n";
    	}
    
    	if(cnSK(2,"127.0.0.1",3636,sk) == SOCKET_ERROR) {
    		WSACleanup();
    		closesocket(sk);
    		std::cerr << "* CONNESSIONE:     ERRORE *\n";
    		return (3);
    	} else {
    		std::cout << "* CONNESSIONE:     ATTIVA *\n";
    	}
    	std::cout << "***************************\n";
    
    	if(getSvMex(sk) <=0) {
    		std::cerr << "ERRORE!\n";
    		WSACleanup();
    		closesocket(sk);
    		return (4);
    	}
    
    	while(true) {
    		if(sendClMex(sk)<= 0) break;
    		if(getSvMex(sk) <= 0) break;
    	}
    	
    	WSACleanup();
    	closesocket(sk);
    	return (0);
    }
    
    int initWsaData(int a, int b) {
    	WSADATA wsaData;
    	int res;
    	res = WSAStartup(MAKEWORD(a, b), &wsaData);
    	return (res);
    }
    
    int initSK(int af, int type, int proto) {
    	UINT_PTR res;
    	res = socket(af, type, proto);
    	return (res);
    }
    
    int cnSK(int af, const char *ip, u_short port, SOCKET s) {
    	int res;
    	sockaddr_in addr;
    	addr.sin_family = af;
    	addr.sin_addr.s_addr = inet_addr(ip);
    	addr.sin_port = htons(port);
    
    	res = connect(s, (SOCKADDR*)&addr, sizeof(addr));
    	return (res);
    }
    
    int getSvMex(SOCKET s) {
    	char buf[256];
    	int by = 0;
    
    	std::cout << "SERV << ";
    	by = recv(s, buf, sizeof(buf), NULL);
    	if(by < 0) {
    		std::cout << "ERRORE!\n";
    		return (0);
    	}
    
    	if(by > 0) displayBuf(buf, by);
    
    	return (by);
    }
    
    int sendClMex(SOCKET s) {
    	int by(0), len(0), i(0);
    	char buf[256];
    	
    	std::cout << "CLIENT: ";
    	std::cin.getline(buf, sizeof(buf));
    	
    	len = strlen(buf);
    	do{
    		if(send(s, &buf[i], sizeof(char), NULL)<=0) {
    			by = 0;
    			break;
    		}
    		i++;
    		by = i;
    	}while(i <= len);
    
    	return by;
    }
    
    void displayBuf(char buf[], int lim) {
    	int len(lim--);
    	buf[len] = '\0';
    	for(int i=0; i<=len; i++)
    		std::cout << buf[i];
    
    	std::cout << '\n';
    }

  8. #8
    Utente di HTML.it
    Registrato dal
    Apr 2005
    Messaggi
    38
    Ciao,
    Volevo dire che ho risolto il problema aggiungendo alla fine della stringa che invio al server, consecutivamente, i caratteri '\r','\n'.

    In questo modo ricevo ora qualsiasi risposta dal server.
    Grazie comunque.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2026 vBulletin Solutions, Inc. All rights reserved.