View Full Version : [C++] Socket con Borland Builder C++
ciao,
ho preso in prestito questa porzione di codice in stile Borland Builder C++ il quale una volta inserito nell'evento approriato, prende tutto, nel mio caso mi interessa testo in formato ASCII, che viene inviato da un client e lo visualizza nel componente Memo dell'aplicativo server.
Problema: inviando n volte il medesimo file, a volte viene troncato in coda ed a volte manca la testa del file; altre ancora vengono prelevati solo 2 o più caratteri. Avete conoscenza di questo funzionamento randomico della VCL?
p.s.
anche terminando Buffer a NULL il risultato è il medesimo.
note: la mia convinzione è che il protocollo TCP/IP dovrebbe garantirmi la ritrasmissione nel caso di perdita di pacchetti.
grazie
int Size=ClientSocket1->Socket->ReceiveLength();
char *Buffer = new char[Size];
ClientSocket1->Socket->ReceiveBuf(Buffer,Size);
Memo1->Lines->Add(Buffer);
http://forum.html.it/forum/showthread.php?threadid=610596
karch_kiraly
21-06-2012, 06:56
Non conosco il Borland builder c++. Per certo utilizzando il protocollo TCP hai la garanzia di ricezione dei dati trasmessi (a differenza dell'UDP).
Non conosco il Borland builder c++. Per certo utilizzando il protocollo TCP hai la garanzia di ricezione dei dati trasmessi (a differenza dell'UDP).
grazie per la conferma, difatti era quello che mi ricordavo
scusate ma mi viene un dubbio se sia legale o meno inviare dati ad un server in questo modo:
while ( fgets(linea,sizeof(linea),fp) != NULL)
{
if( ClientSocket1->Active )
ClientSocket1->Socket->SendBuf(linea,strlen(linea));
}
cioè una linea alla volta presa da disco.
Non credo che si debba creare preventivamente, allocandolo, un buffer gigantesco per poi inviarlo vero?
lorenzo001
21-06-2012, 14:21
Puoi inviare i dati come vuoi. Però, dalla parte di chi riceve, come si fa a determinare quanti caratteri ricevuti fanno parte della stringa?
Puoi inviare i dati come vuoi. Però, dalla parte di chi riceve, come si fa a determinare quanti caratteri ricevuti fanno parte della stringa?
se ho capito la tua domanda, ci pensa la chiamata:
int size=ServerSocket1->Socket->ReceiveLength();
unico dubbio è che non so se la dimensione ritornata si riferisce ad un pacchetto (porzione del file inviato dal client) oppure alla dimensione totale del file che verrà inviato da un client.
Facendo delle prove per uno stesso file ho notato che ogni volta size è differente; a volte ha la dimensione dell'intero file, a volte solo pochi caratteri.
Se la size si riferisce al payload di un solo pacchetto allora avrei scoperto dove sta l'erore, in caso contrario allora c'è un problema nelle socket ma ho qualche dubbio.
ESSE-EFFE
21-06-2012, 20:23
scusate ma mi viene un dubbio se sia legale o meno inviare dati ad un server in questo modo:
while ( fgets(linea,sizeof(linea),fp) != NULL)
{
if( ClientSocket1->Active )
ClientSocket1->Socket->SendBuf(linea,strlen(linea));
}
cioè una linea alla volta presa da disco.
Non credo che si debba creare preventivamente, allocandolo, un buffer gigantesco per poi inviarlo vero?
Ammesso che non ci siano inghippi a leggere il file in quel modo, vedo due problemi: il primo è che la SendBuf potrebbe sollevare un'eccezione (che dal codice non sembra gestita). Il secondo è che bisognerebbe verificare il valore di ritorno della SendBuf, per controllare che il buffer sia stato effettivamente trasmesso (accodato) altrimenti va gestito opportunamente l'errore.
Inoltre, quell'if all'interno del ciclo penso sia inutile.
ESSE-EFFE
21-06-2012, 20:31
se ho capito la tua domanda, ci pensa la chiamata:
int size=ServerSocket1->Socket->ReceiveLength();
unico dubbio è che non so se la dimensione ritornata si riferisce ad un pacchetto (porzione del file inviato dal client) oppure alla dimensione totale del file che verrà inviato da un client.
Facendo delle prove per uno stesso file ho notato che ogni volta size è differente; a volte ha la dimensione dell'intero file, a volte solo pochi caratteri.
Se la size si riferisce al payload di un solo pacchetto allora avrei scoperto dove sta l'erore, in caso contrario allora c'è un problema nelle socket ma ho qualche dubbio.
Non c'è nessun problema nei socket. Quella dimensione ovviamente è pari alla quantità dei byte a disposizione (da leggere). Non è detto (ed è improbabile) che coincida con quella del pacchetto inviato lato client. Ancora più improbabile che coincida con la dimensione del file (salvo casi particolari).
Non c'è nessun problema nei socket. Quella dimensione ovviamente è pari alla quantità dei byte a disposizione (da leggere). Non è detto (ed è improbabile) che coincida con quella del pacchetto inviato lato client. Ancora più improbabile che coincida con la dimensione del file (salvo casi particolari).
vuoi dire che per ricevere il file completo mi servono n chiamate a quella funzione?
Se è così allora il mio problema è di concetto e del tipo:
FILE *fp;
fp=fopen("prova.txt","w");
int size=ServerSocket1->Socket->ReceiveLength();
char *Buffer = new char[Size];
ServerSocket1->Socket->ReceiveBuf(Buffer,Size);
fprintf(fp,"%s",Buffer);
fclose(fp);
tralasciando le inesattezze del codice, sto pretendendo in quel modo di salvare tutto il file inviato dal client con un'unica chiamata a ReceiveBuf()?
Spero si capisca la mia affermazione.
ESSE-EFFE
22-06-2012, 08:45
vuoi dire che per ricevere il file completo mi servono n chiamate a quella funzione?
Se è così allora il mio problema è di concetto e del tipo:
FILE *fp;
fp=fopen("prova.txt","w");
int size=ServerSocket1->Socket->ReceiveLength();
char *Buffer = new char[Size];
ServerSocket1->Socket->ReceiveBuf(Buffer,Size);
fprintf(fp,"%s",Buffer);
fclose(fp);
tralasciando le inesattezze del codice, sto pretendendo in quel modo di salvare tutto il file inviato dal client con un'unica chiamata a ReceiveBuf()?
Spero si capisca la mia affermazione.
Esatto, per ricevere tutto il file è verosimile che ti servano diverse chiamate alla ReceiveBuf (o ReceiveText). Non puoi farlo con una chiamata unica perchè non funzionerà praticamente mai. Il TCP è un protocollo di trasporto, ma poi è necessario stabilire un protocollo a livello applicativo per far dialogare le parti (client e server).
Esatto, per ricevere tutto il file è verosimile che ti servano diverse chiamate alla ReceiveBuf (o ReceiveText). Non puoi farlo con una chiamata unica perchè non funzionerà praticamente mai. Il TCP è un protocollo di trasporto, ma poi è necessario stabilire un protocollo a livello applicativo per far dialogare le parti (client e server).
ecco perchè facendo n invii il server a volte, il server, riceveva il file completo ed a volte no. Difatto studiano la dimensione del buffer ricevuto dal server questo cambiava randomicamente ogni vota.
Quindi una sorta di carattere o simbolo inviato dal client allo scopo di informare il server della testa e coda del file dovrebbe funzionare vero?
Lato server continui a leggere sino a quando ricevi il carattere speciale di fine file.
Non so se solitamente si segue questa strada, magari c'è un modo più furbo?
ESSE-EFFE
25-06-2012, 14:38
Quindi una sorta di carattere o simbolo inviato dal client allo scopo di informare il server della testa e coda del file dovrebbe funzionare vero?
Lato server continui a leggere sino a quando ricevi il carattere speciale di fine file.
Non so se solitamente si segue questa strada, magari c'è un modo più furbo?
E' una soluzione semplice che può funzionare. Basta che i sincronismi non siano presenti nel file ovviamente.
Altra soluzione comune è quella di inviare un header in cui sia presente la dimensione del file (o comunque dei dati) da inviare. Così facendo si potrebbero trasferire anche altre informazioni, come ad esempio il nome del file.
Oppure si utilizzano protocolli standard più complessi come HTTP o FTP.
E' una soluzione semplice che può funzionare. Basta che i sincronismi non siano presenti nel file ovviamente.
Altra soluzione comune è quella di inviare un header in cui sia presente la dimensione del file (o comunque dei dati) da inviare. Così facendo si potrebbero trasferire anche altre informazioni, come ad esempio il nome del file.
Oppure si utilizzano protocolli standard più complessi come HTTP o FTP.
nel frattempo sto provando ad usare un sistema con due buffer: uno che viene definito ogni volta ed uno dinamico, questo per usare il metodo dell'informazione in testa ed in coda al file.
Un dubbio che ho è come mai se invio prima l'informazione che stabilisce l'inizio del file e poi il corpo ed infine la coda, a volte nella medesima chiamata a ServerSocket1->Socket->ReceiveBuf(Buffer,Size); trovo l'informazione di testa ed il corpo inzieme.
Per farmi capire, si comporta come il buffer di una stampante dove s e non vi sono sufficienti caratteri questa non stampa.
Quello che vorrei ottenere è l'invio della testa del file, del corpo ed infine della coda ed almeno che testa e coda vengano inviati non assieme al corpo: è possibile?
Basta che i sincronismi non siano presenti nel file ovviamente.
dimenticavo: cosa intendi con quella frase?
ESSE-EFFE
25-06-2012, 15:23
Un dubbio che ho è come mai se invio prima l'informazione che stabilisce l'inizio del file e poi il corpo ed infine la coda, a volte nella medesima chiamata a ServerSocket1->Socket->ReceiveBuf(Buffer,Size); trovo l'informazione di testa ed il corpo inzieme.
Evidentemente a livello TCP le due informazioni sono state inviate in un unico pacchetto. Considerando che probabilmente quella che tu chiami "informazione di testa" sarà un byte solo, la cosa è abbastanza logica.
In genere, non si controlla come vengono spediti i byte. Sarebbe una complicazione in più senza alcun vantaggio.
ESSE-EFFE
25-06-2012, 15:30
dimenticavo: cosa intendi con quella frase?
Intendo che i byte utilizzati come sincronismo non devono essere presenti nei dati, altrimenti chi riceve non riuscirebbe a riconoscerli. Quindi, per file di testo problemi non ce ne sono, ma per inviare qualunque tipo di file, utilizza un header.
Considerando che probabilmente quella che tu chiami "informazione di testa" sarà un byte solo, la cosa è abbastanza logica.
perchè parli di un byte?
Io sto usando una intesazione del tipo <INIZIOFILE>, ............ , <FINEFILE> è concettualmente sbagliato?
ESSE-EFFE
25-06-2012, 15:47
perchè parli di un byte?
Io sto usando una intesazione del tipo <INIZIOFILE>, ............ , <FINEFILE>
Perchè sarebbe sufficiente un byte. Ma per il discorso del pacchetto TCP è la stessa cosa. Idem per l'eventuale presenza delle intestazioni all'interno del file.
Perchè sarebbe sufficiente un byte. Ma per il discorso del pacchetto TCP è la stessa cosa. Idem per l'eventuale presenza delle intestazioni all'interno del file.
scusa ma non potrebbe accadere che il byte da te scelto viene confuso con un byte del testo che vuoi ricevere/inviare?
ESSE-EFFE
25-06-2012, 17:06
scusa ma non potrebbe accadere che il byte da te scelto viene confuso con un byte del testo che vuoi ricevere/inviare?
Vedi messaggi precedenti:
Basta che i sincronismi non siano presenti nel file ovviamente.
Intendo che i byte utilizzati come sincronismo non devono essere presenti nei dati, altrimenti chi riceve non riuscirebbe a riconoscerli. Quindi, per file di testo problemi non ce ne sono, ma per inviare qualunque tipo di file, utilizza un header.
grazie
passando alla pratica una cosa del tipo:
int Size=ClientSocket1->Socket->ReceiveLength();
char *Buffer = new char[Size];
ClientSocket1->Socket->ReceiveBuf(Buffer,Size);
if(strstr(Buffer,"<INIZIOFILE>"))
Memo1->Lines->Add(Buffer);
............
............
if(strstr(Buffer,"<FINEFILE>"))
sarebbe funzionale per la tua esperienza?
Mi hai risposto in precedenza dicendomi che è un metodo semplice, ma potrebbe avere malfunzionamenti che non conosco?
ESSE-EFFE
25-06-2012, 19:37
sarebbe funzionale per la tua esperienza?
Dipende da cosa devi fare. Il codice non è completo, quindi non lo posso sapere. Prova.
Mi hai risposto in precedenza dicendomi che è un metodo semplice, ma potrebbe avere malfunzionamenti che non conosco?
Non penso, ma anche qui dipende da un migliaio di fattori.
l'idea è questa
void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
TCustomWinSocket *Socket)
{
int Size = Socket->ReceiveLength();
char *Buf = (char *)malloc(Size * sizeof(char *));
int ByteRecived = Socket->ReceiveBuf(Buf, Size);
Buf[Size] = '\0';
if(Size > 0)
{
Buffer = (char *)realloc(Buffer,strlen(Buffer) + Size );
strcat(Buffer,Buf);
free(Buf);
}
if(strstr(Buffer,",FINEFILE;")) {
Memo1->Lines->Add(Buffer);
free(Buffer);
}
}
dove Buffer è una variabile globale che viene allocata ed inizializzata a NULL ogni volta che un client si connette al server per inviare un file.
quali sono, se noti, i casi in cui un invio di dati da client verso server falliscono?
Ho il seguente problema:
- il client si connette
- invia i dati al server
- il server riceve i dati
- il client si disconnette
ripetuti i passi elencati sopra per n volte, capita che:
- il client si connette
- invia i dati al server
- il server NON riceve i dati
- il client si disconnette
nessuna segnalazione di errore
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.