Questo sito utilizza cookies, anche di terze parti, per mostrare pubblicità e servizi in linea con il tuo account. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - [RISOLTO] - Sockets e send()
Forum - C/C++ - [RISOLTO] - Sockets e send()

Avatar
Danyez (Normal User)
Newbie


Messaggi: 15
Iscritto: 28/01/2010

Segnala al moderatore
Postato alle 1:38
Martedì, 16/08/2011
Salve, ragazzi !
Mi vedo costretto ad usufruire della vostra gentilezza chiedendovi un aiuto.

Ho creato un file server.c ed un file client.c perfettamente funzionanti. Il file client.c invia un determinato buffer al file server.c che, ricevendolo, lo inserisce in un file di testo chiamato buffer.txt

Fin qui tutto bene, fino al momento in cui non ho deciso che non mi bastava :P .. ho tentato innanzitutto l'invio di un buffer più grande di 8 kb (limite massimo buffer) ed ho scoperto con mio grande piacere che l'applicazione comunque riceveva tutto il buffer (diviso in porzioni di 8 kb). Poi ho deciso di utilizzare un vecchio esperimento che feci (un semplice copia-incolla in C, un'applicazione che copia byte per byte l'intero file e lo riscrive) applicato a questo progetto : l'invio di un file jpeg sottoforma di stream e la riscrittura da parte di server.c in un file di nome buffer.jpg. Qui sono nati i miei problemi.

Questa è la parte di codice, in Client.c, che legge il file e lo memorizza in un buffer.
Codice sorgente - presumibilmente Delphi

  1. FILE *fsource;
  2.     ..
  3.     ..
  4.     ..
  5.     int filesize;
  6.     if ((fsource = fopen(argv[3],"r")))
  7.     {
  8.     fseek(fsource, 0, SEEK_END); //sposto cursore alla fine
  9.     filesize = ftell(fsource);
  10.         printf("Lunghezza file : %d \n",filesize); //leggo posizione cursore per lunghezza file
  11.     char buffer[filesize]; //dichiaro buffer della grandezza del file
  12.     fseek(fsource, 0, SEEK_SET);
  13.     fread(buffer,sizeof(buffer),1,fsource);



Questa è la parte di codice, in Client.c, che invia il buffer.
Codice sorgente - presumibilmente Plain Text

  1. send(sock,buffer,sizeof(buffer),0);




Questa è la parte di codice, in Server.c, che ricostruisce lo stream creando il file buffer.jpg
Codice sorgente - presumibilmente C/C++

  1. FILE *ftext;
  2.         int carat;
  3.         while ((carat=recv(sd_client, buff, sizeof(buff), 0))>0)
  4. {
  5.         ftext = fopen("buffer.jpg","a+");
  6.         printf("Dati ricevuti. \n");
  7.         fwrite(&buff,strlen(buff),1,ftext);    
  8.         char *ip_address = inet_ntoa(client_addr.sin_addr);
  9.         printf("IP: %s\n", ip_address);
  10.         printf("------------------------\n");
  11. }
  12. fclose(ftext);



Il risultato che ottengo è un file di 1,1 kb ovviamente non leggibile. La cosa non ha il minimo senso, poichè cambia praticamente pochissimo dal codice per il passaggio di un testo (e ripeto, ho provato ad inviare con un ciclo for un ammontare di 'A' pari a 400 kb di buffer e non ho avuto il minimo problema !).

La domanda principale è : Perchè si comporta in questo modo ?

Vi sarò enormemente grato se vorrete aiutarmi :)

------------------------------------------------------------------------------------------------------------
AGGIORNAMENTI :

Ringrazio chiunque abbia letto anche solo per un attimo il mio thread bruciando qualche neurone in suo onore, rendendo noto che ho risolto il problema.


Avevo già intuito, ieri notte, che il problema fosse dato dalla lettura dello stream in cui vi era la possibilità di incontrarne una parte (erroneamente) identificata come fine stringa. Ho quindi deciso di adottare un sistema che leggesse lo stream e lo copiasse carattere per carattere in modo da non andare incontro al problema. Lascio qui la soluzione nel caso qualcuno ne avesse bisogno :)


Codice modificato in : client.c
Codice sorgente - presumibilmente C/C++

  1. for (n=0;n<filesize;n++) {
  2.    a[0]=buffer[n];
  3.    send(sock,a,1,0);
  4. }



Codice modificato in : server.c
Codice sorgente - presumibilmente C/C++

  1. while ((carat=recv(sd_client, buff, sizeof(buff), 0))>0)
  2. {
  3.         for (nb=0;nb<carat;nb++)
  4. {
  5.         ftext = fopen("buffer.jpg","ab");
  6.         b[0] = buff[nb];
  7.         fwrite(b,1,1,ftext);
  8.         fclose(ftext);
  9. }
  10. }



Il codice è ovviamente ancora un pò da sistemare e ripulire, ma comunque sia è questo il metodo che ho usato per risolvere il problema. :D


Grazie a tutti, comunque ! :k: :k:

Ultima modifica effettuata da Danyez il 16/08/2011 alle 10:14


http://danyez.net < Un mio piccolo blog di recente nascita.
PM
Avatar
comina8 (Normal User)
Pro


Messaggi: 86
Iscritto: 18/06/2011

Up
0
Down
V
Segnala al moderatore
Postato alle 10:10
Martedì, 16/08/2011
Avevo implementato qualcosa di simile anch'io..
Il modo migliore per farlo è leggere pezzi di file e inviarli.

Prima di tutto il tuo server non sa di quanti byte è composto il file, quindi riceve un array di N elementi che non è detto siano uguali alla grandezza del file.
Seconda cosa per i file più grossi (film o altro) non sarebbe possibile fare come hai fatto tu...

Fino a ftell(..) è corretto, dopo di questo devi inviare al server la grandezza del file

int Lun=ftell(fp);
send(sock,&Lun,sizeof(int),0);

recv(sock,&Lun,sizeof(int),0);

Poi esegui un for che va da i=0 fino a i<(Lun/LUNGHEZZA_MASSIMA).

LUNGHEZZA_MASSIMA è una define che dev'essere UGUALE sia nel server che nel client.

Dentro il ciclo leggi fread(array,LUNGHEZZA_MASSIMA,sizeof(char),fp);
elementi e li invii al server send(sock,array,LUNGHEZZA_MASSIMA,0);

recv(sock,array,LUNGHEZZA_MASSIMA,0);

Una volta uscito dal for ti chiedi se i%LUNGHEZZA_MASSIMA non è uguale a zero (se ci sono dei byte nel file rimasti) e leggi fread(array,i%LUNGHEZZA_MASSIMA,sizeof(char),fp); e invii al server, che eseguirà lo stesso controllo (visto che sa anche lui la lunghezza).

Chiudi il file e dovrebbe esserci tutto.
Per iniziare LUNGHEZZA_MASSIMA impostala a 512 che va abbastanza bene, inviando troppi byte per volta va fin più lento...

PS: l'array dichiaralo di LUNGHEZZA_MASSIMA...

PPS: se il file fosse più piccolo di lunghezza massima ti conviene eseguire un controllo (LUNGHEZZA_MASSIMA impostalo come normale unsigned long)

#define MAX 512
if(LunghezzaFile<MAX)
   LUNGHEZZA_MASSIMA=1; //tanto se è più piccolo di mezzo mb te lo invia in             un attimo
else
   LUNGHEZZA_MASSIMA=MAX;

char Array[MAX];

Ultima modifica effettuata da comina8 il 16/08/2011 alle 10:17
Grazie mille. :D Proverò anche il tuo metodo e ti chiedo, gentilmente, di dare anche un'occhiata al metodo che ho adottato per risolvere il problema nello specifico :) - Danyez - 16/08/11 10:17
Il problema era che il server non sapeva la lunghezza del file e che inviando tutto il file in una volta sola si "perde" qualche pezzo, non ce la fa proprio, infatti inviando carattere per carattere il programma funziona. Ti consiglio comunque il mio metodo (al quale stai comunque arrivando - comina8 - 16/08/11 10:20
anche tu con la logica) per la maggiore velocità di trasferimento e la maggior correttezza di invio (si invia l'esatto numero di byte) oltre ad essere generale per tutti i file... - comina8 - 16/08/11 10:21
Senti, posso chiederti un metodo per contattarti in privato ? Ho alcune idee per migliorare il trasferimento ed il thread non mi sembra il posto adatto per parlarne. :) - Danyez - 16/08/11 10:38
Puoi contattarmi con i pm se lo desideri, anche se considero di maggior aiuto per utenti futuri la discussione aperta nel forum... - comina8 - 16/08/11 11:28
PM