PDA

View Full Version : [C++] ancora problemi con le socket


misterx
12-03-2013, 21:18
non sono ancora riuscito a domare questa parte della programmazione in quanto ne so ancora poco.

Premetto che sto usando Borland Builder C++ ma non credo sia fondamentale il compilatore ma i concetti che vi stanno dietro.

Ho scritto un piccolo server che resta in ascolto su una determinata porta e nel momento in cui un client si connette inizia la ricezione dei dati.
Il problema è che lato server a volte i dati non arrivano tutti e sono convinto che non so qualcosa di tremendamente importante. Cercando in rete ho trovato istruzioni del tipo:

int Size = Socket->ReceiveLength();

da che ho capito con tale informazione il server sa quanti dati verranno spediti dal client ed in base a questo dato, il server prepara un buffer atto a contenere i dati

char *Buf;
int ByteRicevuti;
Buf = new char[Size];
ByteRicevuti=Socket->ReceiveBuf(Buf, Size);

queto punto mi è poco chiaro e cioè: può accadere che il numero di byte negoziati attraverso la int Size = Socket->ReceiveLength(); una volta invocata la Socket->ReceiveBuf(Buf, Size); siano inferiori?

Se così fosse, si dovrebbe inserire un while appropriato del tipo:

while (ByteRicevuti > 0)
ByteRicevuti=Socket->ReceiveBuf(Buf, Size);

????

Ho notato poi che se il testo inviato dal client ha una dimensione inferiore a 8192 caratteri tutto sembra funzionare, se è maggiore il server non riceve mai tutti i caratteri.



grazie a tutti coloro che risponderanno al mio messaggio.

sottovento
13-03-2013, 04:41
int Size = Socket->ReceiveLength();

Socket e' un oggetto di una tua classe, o e' una classe di Borland?


char *Buf;
int ByteRicevuti;
Buf = new char[Size];
ByteRicevuti=Socket->ReceiveBuf(Buf, Size);



Ho notato poi che se il testo inviato dal client ha una dimensione inferiore a 8192 caratteri tutto sembra funzionare, se è maggiore il server non riceve mai tutti i caratteri.


Non conosco Borland e le sue foundation classes (o come hanno deciso di chiamarle).
Ad ogni modo, le chiamate standard per la lettura di una socket restituiscono sempre il numero di byte DISPONIBILI nel buffer di ricezione al momento dell'invocazione.

Se per esempio fai una read() di 1000 byte ma al momento ne sono disponibili solo 100, ti verranno ritornati solo i 100 disponibili.
Immagino che le classi Borland semplicemente incapsulino 'sta cosa senza cambiarne il modo di funzionamento. Quindi direi di si, e' standard.

misterx
13-03-2013, 06:14
Socket e' un oggetto di una tua classe, o e' una classe di Borland?

Non conosco Borland e le sue foundation classes (o come hanno deciso di chiamarle).
Ad ogni modo, le chiamate standard per la lettura di una socket restituiscono sempre il numero di byte DISPONIBILI nel buffer di ricezione al momento dell'invocazione.

Se per esempio fai una read() di 1000 byte ma al momento ne sono disponibili solo 100, ti verranno ritornati solo i 100 disponibili.
Immagino che le classi Borland semplicemente incapsulino 'sta cosa senza cambiarne il modo di funzionamento. Quindi direi di si, e' standard.

Socket è un componente, come viene chiamato da Borland che mette a disposizione proprierà, metodi ed eventi.

Tanto per comprendere il meccanismo, di solito il trasferimento di un file attraverso il protocollo TCP/IP come avviene?
La mia idea è: il client si connette e stabilisce col server la dimensione di ogni pacchetto inviato/ricevuto. Il server quindi chiede al client attraverso la int Size = Socket->ReceiveLength(); la dimensione del pacchetto che vuole inviare.
A questo punto il server alloca dinamicamente un buffer atto a contenere il pacchetto.
Supponiamo che il client vuole spedire al server 1000 byte.
A questo punto il server usando la ByteRicevuti=Socket->ReceiveBuf(Buf, Size);
a) riceve e riempie il buffer in un colpo solo con 1000 byte
b) a causa di qualcosa che non conosco arrivano 10 pacchetti da 100 byte

ma a questo punto a che servirebbe settare un buffer iniziale da 100 byte?

Purtroppo non trovo documentazione in rete, nemmeno sui vari manuali.

The_ouroboros
13-03-2013, 07:27
Ma non è il max buffer che il server alloca..

Inviato dal mio Sony Xperia P

misterx
13-03-2013, 07:46
Ma non è il max buffer che il server alloca..

Inviato dal mio Sony Xperia P


cosa vuoi dire?

sottovento
13-03-2013, 08:13
int Size = Socket->ReceiveLength();

Questa mi turba. Siccome viaggiamo su TCP/IP, questa potrebbe essere (secondo me):
1 - la dimensione del pacchetto tcp/ip (8192 sembrano molti ma e' ancora accettabile);
2 - la dimensione del buffer di ricezione;
3 - l'ammontare dei dati attualmente ricevuti, in attesa di esser letti dal tuo programma;
4 - un eventuale protocollo di comunicazione annegato all'interno dell'oggetto Socket di Borland, con il quale client/server si trasmettono prima la dimensione dei dati e poi i dati stessi. Non e' poi cosi' strano, l'azienda per cui sto ora lavorando fa proprio cosi'.

A orecchio la #2 sembra la piu' realistica.
Sia quel che sia, in libreria troverai sempre (SEMPRE) metodi di lettura che funzionano cosi: se chiedi 1000 byte, otterrai AL MASSIMO 1000 byte, ma tutti i numeri compresi tra -1 e 1000 (estremi inclusi) sono accettabili.

Per quanto riguarda la tua domanda: sapere quel numero e' importante nel caso abbia bisogno di dimensionare il buffer di ricezione.
Come saprai, TCP/IP riceve i dati e li mette in quel buffer, dopo di che li conferma. Nel caso il buffer sia pieno (per esempio, stai facendo dell'elaborazione un po' pesante con i dati gia' ricevuti), non ci sarebbe piu' spazio per i nuovi dati e tcp/ip automaticamente smetterebbe di confermare i dati alla controparte. La controparte, allora, carichera' un timer e allo scadere provera' a ritrasmettere, sperando in un esito migliore. (TCP/IP non perde i dati dietro strada)
E cosi' via, fino alla ricezione di una conferma o allo scadere del tempo massimo.
E' quindi un valore importante per tenere viva e agile la comunicazione.


Socket è un componente, come viene chiamato da Borland che mette a disposizione proprierà, metodi ed eventi.

Tanto per comprendere il meccanismo, di solito il trasferimento di un file attraverso il protocollo TCP/IP come avviene?
La mia idea è: il client si connette e stabilisce col server la dimensione di ogni pacchetto inviato/ricevuto. Il server quindi chiede al client attraverso la int Size = Socket->ReceiveLength(); la dimensione del pacchetto che vuole inviare.
A questo punto il server alloca dinamicamente un buffer atto a contenere il pacchetto.
Supponiamo che il client vuole spedire al server 1000 byte.
A questo punto il server usando la ByteRicevuti=Socket->ReceiveBuf(Buf, Size);
a) riceve e riempie il buffer in un colpo solo con 1000 byte
b) a causa di qualcosa che non conosco arrivano 10 pacchetti da 100 byte

ma a questo punto a che servirebbe settare un buffer iniziale da 100 byte?

Purtroppo non trovo documentazione in rete, nemmeno sui vari manuali.

WarDuck
13-03-2013, 08:51
Socket è un componente, come viene chiamato da Borland che mette a disposizione proprierà, metodi ed eventi.

Tanto per comprendere il meccanismo, di solito il trasferimento di un file attraverso il protocollo TCP/IP come avviene?


Questo dipende esclusivamente dal lato applicativo, ovvero da te.

Anche i buffer di invio e ricezione lato applicazione dipendono da te.

Un sistema semplice potrebbe essere:

1) client si connette al server e manda la dimensione del file da inviare (FSIZE)
2) server manda un ACK o un NACK a seconda dei casi (esempio banale, verifico se c'è abbastanza spazio su disco, altrimenti potrei anche decidere di terminare la connessione).
3) se client ha ricevuto ACK comincia a mandare il file in chunk da 4KB
4) il server riceve in chunk da 4KB e scrive su disco chunk di 4KB

La terminazione può essere gestita in vari modi:

a) il client si disconnette quando finisce di inviare il file, questo si traduce nella ricezione di un particolare messaggio lato server
b) il server smette di scrivere quando ha ricevuto FSIZE bytes e si prepara a ricevere una nuova size e un nuovo file (lasciando aperta la connessione)

Chiaramente quanto farlo complicato dipende esclusivamente da te, puoi anche pensare ad un sistema per cui puoi inviare comandi particolari per segnalare determinati eventi.


La mia idea è: il client si connette e stabilisce col server la dimensione di ogni pacchetto inviato/ricevuto. Il server quindi chiede al client attraverso la int Size = Socket->ReceiveLength(); la dimensione del pacchetto che vuole inviare.

A questo punto il server alloca dinamicamente un buffer atto a contenere il pacchetto.


Non è necessario, tipicamente si usa un singolo buffer statico, quanto leggere tipicamente lo decidi te, se vuoi usare un buffer da 4KB leggerai sempre al più 4096 bytes (chiaramente ad ogni lettura sovrascriverai il contenuto precedente).

Comunque il mio consiglio per capire meglio cosa stai facendo è affidarti alle librerie standard fornite con il sistema operativo.

misterx
13-03-2013, 08:51
int Size = Socket->ReceiveLength();

Questa mi turba. Siccome viaggiamo su TCP/IP, questa potrebbe essere (secondo me):
1 - la dimensione del pacchetto tcp/ip (8192 sembrano molti ma e' ancora accettabile);
2 - la dimensione del buffer di ricezione;
3 - l'ammontare dei dati attualmente ricevuti, in attesa di esser letti dal tuo programma;
4 - un eventuale protocollo di comunicazione annegato all'interno dell'oggetto Socket di Borland, con il quale client/server si trasmettono prima la dimensione dei dati e poi i dati stessi. Non e' poi cosi' strano, l'azienda per cui sto ora lavorando fa proprio cosi'.

A orecchio la #2 sembra la piu' realistica.
Sia quel che sia, in libreria troverai sempre (SEMPRE) metodi di lettura che funzionano cosi: se chiedi 1000 byte, otterrai AL MASSIMO 1000 byte, ma tutti i numeri compresi tra -1 e 1000 (estremi inclusi) sono accettabili.

Per quanto riguarda la tua domanda: sapere quel numero e' importante nel caso abbia bisogno di dimensionare il buffer di ricezione.
Come saprai, TCP/IP riceve i dati e li mette in quel buffer, dopo di che li conferma. Nel caso il buffer sia pieno (per esempio, stai facendo dell'elaborazione un po' pesante con i dati gia' ricevuti), non ci sarebbe piu' spazio per i nuovi dati e tcp/ip automaticamente smetterebbe di confermare i dati alla controparte. La controparte, allora, carichera' un timer e allo scadere provera' a ritrasmettere, sperando in un esito migliore. (TCP/IP non perde i dati dietro strada)
E cosi' via, fino alla ricezione di una conferma o allo scadere del tempo massimo.
E' quindi un valore importante per tenere viva e agile la comunicazione.

siccome in rete trovo tutti esempi come quello da me postato, credo anch'io che sia la #2 il significato della

int Size = Socket->ReceiveLength();

difatti dagli esempi in rete, subito dopo questa chiamata segue sempre una allocazione del buffer

char *Buf;
int ByteRicevuti;
Buf = new char[Size];
ByteRicevuti=Socket->ReceiveBuf(Buf, Size);

scusate per le ripetizioni ma servono per capire.

L'ultimo dubbio che mi resta da sfatare è se ByteRicevuti può avere un valore inferiore del Size stabilito all'inizio tra client e server.
Se così fosse, avrebbe senso una cosa del tipo

while( (ByteRicevuti=Socket->ReceiveBuf(Buf, Size)) > 0);

WarDuck
13-03-2013, 09:04
siccome in rete trovo tutti esempi come quello da me postato, credo anch'io che sia la #2 il significato della

int Size = Socket->ReceiveLength();

difatti dagli esempi in rete, subito dopo questa chiamata segue sempre una allocazione del buffer

char *Buf;
int ByteRicevuti;
Buf = new char[Size];
ByteRicevuti=Socket->ReceiveBuf(Buf, Size);

scusate per le ripetizioni ma servono per capire.

L'ultimo dubbio che mi resta da sfatare è se ByteRicevuti può avere un valore inferiore del Size stabilito all'inizio tra client e server.
Se così fosse, avrebbe senso una cosa del tipo

while( (ByteRicevuti=Socket->ReceiveBuf(Buf, Size)) > 0);

Tipicamente la receive può tornare 0 o -1 a seconda che si sia riscontrata una condizione tipo EOF (cioè per esempio l'altro lato ha chiuso la connessione) o un errore.

Per questo si usa un ciclo come quello da te postato.

Quanto leggere lo decidi esclusivamente tu come Size, non è possibile chiaramente che ByteRicevuti > Size.

Invece è perfettamente possibile avere ByteRicevuti < Size.

Size indica il numero massimo di bytes da leggere ad ogni chiamata.

misterx
13-03-2013, 09:20
Tipicamente la receive può tornare 0 o -1 a seconda che si sia riscontrata una condizione tipo EOF (cioè per esempio l'altro lato ha chiuso la connessione) o un errore.

Per questo si usa un ciclo come quello da te postato.

Quanto leggere lo decidi esclusivamente tu come Size, non è possibile chiaramente che ByteRicevuti > Size.

Invece è perfettamente possibile avere ByteRicevuti < Size.

Size indica il numero massimo di bytes da leggere ad ogni chiamata.

grazie per le risposte.

Vediamo se ho capito; lato server mi faccio spedire le dimensioni del file, ad esempio 100KB.
Attraverso la int Size = Socket->ReceiveLength(); ottengo la dimensione di ogni singolo pacchetto che mi invierà il client e queste dimensioni possono essere variabili in quanto son legate al traffico sulla rete.
Dimensiono il mio buffer e attraverso il while() le riempio tutto, quindi lo uso e incremento una variabile che mi dice, rispetto ai 100KB attesi quanto ho letto sino ad ora.
Di nuovo int Size = Socket->ReceiveLength(); quindi un nuovo buffer e ancora while(), tutto questo sino a quando la mia variabile contatrice vale 100KB.

Ipotizzando che il ragionamento sia corretto, potrei invece di usare una variabile contatrice inserire in coda al testo che riceverà il server una cosa del tipo: "xyz123" ?
In questo secondo caso continuerei a creare buffer ed a distruggere buffer sino a quando non leggo quello che mi aspetto in coda.

grazie 1000

sottovento
13-03-2013, 09:33
grazie per le risposte.

Vediamo se ho capito; lato server mi faccio spedire le dimensioni del file, ad esempio 100KB.
Attraverso la int Size = Socket->ReceiveLength(); ottengo la dimensione di ogni singolo pacchetto che mi invierà il client e queste dimensioni possono essere variabili in quanto son legate al traffico sulla rete.
Dimensiono il mio buffer e attraverso il while() le riempio tutto, quindi lo uso e incremento una variabile che mi dice, rispetto ai 100KB attesi quanto ho letto sino ad ora.
Di nuovo int Size = Socket->ReceiveLength(); quindi un nuovo buffer e ancora while(), tutto questo sino a quando la mia variabile contatrice vale 100KB.

Ipotizzando che il ragionamento sia corretto, potrei invece di usare una variabile contatrice inserire in coda al testo che riceverà il server una cosa del tipo: "xyz123" ?
In questo secondo caso continuerei a creare buffer ed a distruggere buffer sino a quando non leggo quello che mi aspetto in coda.

grazie 1000

Per quanto ci siamo detti, puoi anche non chiamare la Socket->ReceiveLength(): semplicemente dichiari il tuo buffer e cominci a leggere. Quello che fa la rete in mezzo e quello che fa il driver, tutto sommato, non ti interessa, no?
Quindi e' anche piu' facile:

1 - il server ti dice che il file e' lungo xxxxxxx bytes (ATTENZIONE - va da se' che siccome questo numero sara' su piu' bytes, potrebbe essere ricevuto anche lui in tempi diversi);
2 - fintanto che ricevi i byte
2.1 - li metti nel tuo buffer;
2.2 - li scrivi/elabori;
2.3 - sei pronto a ricominciare usando lo stesso buffer

misterx
13-03-2013, 10:17
Per quanto ci siamo detti, puoi anche non chiamare la Socket->ReceiveLength(): semplicemente dichiari il tuo buffer e cominci a leggere. Quello che fa la rete in mezzo e quello che fa il driver, tutto sommato, non ti interessa, no?
Quindi e' anche piu' facile:

1 - il server ti dice che il file e' lungo xxxxxxx bytes (ATTENZIONE - va da se' che siccome questo numero sara' su piu' bytes, potrebbe essere ricevuto anche lui in tempi diversi);
2 - fintanto che ricevi i byte
2.1 - li metti nel tuo buffer;
2.2 - li scrivi/elabori;
2.3 - sei pronto a ricominciare usando lo stesso buffer


quindi potre allocare da subito ad esempio un buffer da 100KB e continuare a leggere sino a quando trovo il marcatore di fine file "xyz123"

sottovento
13-03-2013, 10:52
quindi potre allocare da subito ad esempio un buffer da 100KB e continuare a leggere sino a quando trovo il marcatore di fine file "xyz123"

Per esempio, si. Ma io cercherei una soluzione piu' generale (sai, se ci fosse xyz123 nel file sarebbe un bel casino...).
Quello che avevi detto prima (i.e. farsi spedire la lunghezza del file) non e' male, anzi....

misterx
13-03-2013, 11:05
Per esempio, si. Ma io cercherei una soluzione piu' generale (sai, se ci fosse xyz123 nel file sarebbe un bel casino...).
Quello che avevi detto prima (i.e. farsi spedire la lunghezza del file) non e' male, anzi....

nel frattempo ho scoperto che richiamare la Socket->ReceiveLength(); è obbligatorio, altrimenti la Socket->ReceiveBuf(Buf, Size); non funziona. Di sicuro inizializza qualcosa di cui necessita il Bulder ma non documentato, almeno, non nella documentazione che ho io.

sottovento
13-03-2013, 11:19
nel frattempo ho scoperto che richiamare la Socket->ReceiveLength(); è obbligatorio, altrimenti la Socket->ReceiveBuf(Buf, Size); non funziona. Di sicuro inizializza qualcosa di cui necessita il Bulder ma non documentato, almeno, non nella documentazione che ho io.

Scusa ma a questo punto perche' non usi direttamente le socket, invece di affidarti ad una libreria che non si capisce come funziona?
Se proprio vuoi una libreria che ti semplifichi la vita, puoi comunque cercarne una su internet, usare qt, ....

misterx
13-03-2013, 11:40
Scusa ma a questo punto perche' non usi direttamente le socket, invece di affidarti ad una libreria che non si capisce come funziona?
Se proprio vuoi una libreria che ti semplifichi la vita, puoi comunque cercarne una su internet, usare qt, ....

in ambiente Borland è comodo in quanto gestisci le socket attraverso semplici eventi. La sfortuna è che se l'implementazione delle socket presentano bachi di un qualche genere non si riesce a capirlo.
L'unico modo che ho di verificare sono i byte letti attraverso la Socket->ReceiveBuf(Buf, Size);

Usando una libreria esterna dovrei implementare un thread che mi rimane in ascolto su una determinata porta giusto?

sottovento
13-03-2013, 14:35
in ambiente Borland è comodo in quanto gestisci le socket attraverso semplici eventi.

Questa e' cosa buona e giusta. Intendiamoci, non volevo criticare Borland, che ha sempre fatto ottimi prodotti. Ne facevo solo un problema di documentazione. In effetti poter disporre di eventi in base allo stato della socket e' un bel vantaggio.



La sfortuna è che se l'implementazione delle socket presentano bachi di un qualche genere non si riesce a capirlo.
L'unico modo che ho di verificare sono i byte letti attraverso la Socket->ReceiveBuf(Buf, Size);

Probabilmente non e' un bug, ma solo mancanza di informazioni. Dipende certamente da quello che uno vuol fare, ma spesso perdo la pazienza e cerco qualcos'altro in rete....


Usando una libreria esterna dovrei implementare un thread che mi rimane in ascolto su una determinata porta giusto?
Esistono diverse tecniche. Una di queste e' appunto quella da te accennata.
Ovviamente hanno vantaggi e svantaggi: per esempio, aprire un thread per ogni connessioni ha il vantaggio di essere semplice da realizzare, ma lo svantaggio di non essere "scalabile". Infatti, con questa tecnica potrai trattare solo un numero limitato e relativamente basso di connessioni.
Se il numero di clienti aperti contemporaneamente comincia a salire, avrai bisogno di una soluzione piu' sofisticata

misterx
13-03-2013, 21:02
Questa e' cosa buona e giusta. Intendiamoci, non volevo criticare Borland, che ha sempre fatto ottimi prodotti. Ne facevo solo un problema di documentazione. In effetti poter disporre di eventi in base allo stato della socket e' un bel vantaggio.

infatti uso Borland perchè ho pochissimo tempo a disposizione e mi ritrovo molte cose già pronte e soprattutto grà testate in quanto quello che sto sviluppando è piuttosto critico, se si sbaglia sono dolori.


Chiedo una conferma anche se so che non usate Borland: dopo innumerevoli prove ho notato la seguente situazione usando le seguenti funzioni già citate più volte:

int Size;
char *Buf;
int ByteRicevuti;

Size = Socket->ReceiveLength();
Buf = new char[Size];
ByteRicevuti=Socket->ReceiveBuf(Buf, Size);

inviando testo e stampando innumerevoli volte ottengo che Size e ByteRicevuti sono sempre uguali: potrebbe significare che la ReciveBuf() fa tutto il lavoro autonomamente e mi riempi Buf senza la necessita di un while?

Cioè, tale chiamata ho notato che porta al medesimo risultato

while((ByteRicevuti=Socket->ReceiveBuf(Buf, Size)) > 0);


grazie 1000

sottovento
14-03-2013, 05:52
infatti uso Borland perchè ho pochissimo tempo a disposizione e mi ritrovo molte cose già pronte e soprattutto grà testate in quanto quello che sto sviluppando è piuttosto critico, se si sbaglia sono dolori.


Chiedo una conferma anche se so che non usate Borland: dopo innumerevoli prove ho notato la seguente situazione usando le seguenti funzioni già citate più volte:

int Size;
char *Buf;
int ByteRicevuti;

Size = Socket->ReceiveLength();
Buf = new char[Size];
ByteRicevuti=Socket->ReceiveBuf(Buf, Size);

inviando testo e stampando innumerevoli volte ottengo che Size e ByteRicevuti sono sempre uguali: potrebbe significare che la ReciveBuf() fa tutto il lavoro autonomamente e mi riempi Buf senza la necessita di un while?

Cioè, tale chiamata ho notato che porta al medesimo risultato

while((ByteRicevuti=Socket->ReceiveBuf(Buf, Size)) > 0);


grazie 1000

Non mi fiderei, assolutamente! non so per quale motivo ti ritorni sempre gli stessi valori di Size e ByteRicevuti. Ma quel while ti mette davvero al riparo.
Io lo terrei, pero' ora sono curioso: hai per caso trovato qualche documentazione sulla rete? Qualcosa?

misterx
14-03-2013, 06:14
Non mi fiderei, assolutamente! non so per quale motivo ti ritorni sempre gli stessi valori di Size e ByteRicevuti. Ma quel while ti mette davvero al riparo.
Io lo terrei, pero' ora sono curioso: hai per caso trovato qualche documentazione sulla rete? Qualcosa?

ho letto solo notizie frammentarie ed a quanto ho capito le socket come le sto usando io sono NON bloccanti e per tale ragione viene ritenuto normale per il protocollo TCP/IP tale comportamento. A quanto sembra devo leggere i restanti byte nel buffer di ricezione.

misterx
14-03-2013, 10:43
problema risolto, il segreto era proprio tale linea

while((ByteRicevuti=Socket->ReceiveBuf(Buf, Size)) > 0);

se dovesse servire a qualcuno


void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
TCustomWinSocket *Socket)
{
char *Buf;
String Buffer;
int Size;
int ByteRecived;
int mioheader=0, mioend=0;

Size = Socket->ReceiveLength();

// inizio a costruire il mio buffer
if(Size > 0)
{
Buf = new char[Size];
while( (ByteRecived=Socket->ReceiveBuf(buffer, Size)) > 0 )
{
if( strstr(Buf.c_str(), "INIZIODATI," ) mioheader++
if( strstr(Buf.c_str(), "FINEDATI," ) mioend++
Buffer+=Buf;
}
}

if( mioheader == 1 && mioend == 1 )
{
MiaFunzione();
Buffer="";
}


}

misterx
16-03-2013, 08:21
ciao,
avrò letto quasi tutta la rete :D ma ancora non sono soddisfatto in quanto mi rimangono sempre dei dubbi che non mi permettono di capire sino in fondo se quello che sto facendo ha un senso.

In Borland Builder quando si decide di scrivere un applicativo server, il programmatore ha a disposizione una ricca serie di componenti i quali posseggono metodi (funzioni), proprietà ed eventi.
Una volta implementato un piccolo server, ad esempio, si ha a disposizione l'evento

void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
TCustomWinSocket *Socket)
{
}

che ho già mostrato in altri 3D di cui però non è chiarissimo quante volte viene scatenato.
Supponiamo che un client si connette al server e vuole inviare 1 file da 1 MB; se non erro la dimensione massima di un pacchetto TCP/IP è di 8192 byte quindi, il client deve inviare al server 1048576:8192=128 pacchetti sempre che si abbia la fortuna che i pacchetti siano tutti da 8192 byte.
Se qualcuno che ha avuto a che fare con Borland Builder mi sa dire se l'evento citato sopra viene generato 128 mi farebbe un grandissimo favore. Ho provato ad inserire in quell'evento una variabile contatrice, globale, ed ho notato che inviando un file da qualche centinaio di KB si direbbe che viene generato parecchie volte e si direbbe, tante quanti sono i pacchetti ricevuti dal server: ma è così o c'è dell'altro che non riesco a scovare da nessuna parte?


grazie 1000

WarDuck
16-03-2013, 09:01
ciao,
avrò letto quasi tutta la rete :D ma ancora non sono soddisfatto in quanto mi rimangono sempre dei dubbi che non mi permettono di capire sino in fondo se quello che sto facendo ha un senso.

In Borland Builder quando si decide di scrivere un applicativo server, il programmatore ha a disposizione una ricca serie di componenti i quali posseggono metodi (funzioni), proprietà ed eventi.
Una volta implementato un piccolo server, ad esempio, si ha a disposizione l'evento

void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
TCustomWinSocket *Socket)
{
}

che ho già mostrato in altri 3D di cui però non è chiarissimo quante volte viene scatenato.
Supponiamo che un client si connette al server e vuole inviare 1 file da 1 MB; se non erro la dimensione massima di un pacchetto TCP/IP è di 8192 byte quindi, il client deve inviare al server 1048576:8192=128 pacchetti sempre che si abbia la fortuna che i pacchetti siano tutti da 8192 byte.
Se qualcuno che ha avuto a che fare con Borland Builder mi sa dire se l'evento citato sopra viene generato 128 mi farebbe un grandissimo favore. Ho provato ad inserire in quell'evento una variabile contatrice, globale, ed ho notato che inviando un file da qualche centinaio di KB si direbbe che viene generato parecchie volte e si direbbe, tante quanti sono i pacchetti ricevuti dal server: ma è così o c'è dell'altro che non riesco a scovare da nessuna parte?


grazie 1000

Dipende dal frame ethernet e dall'MTU dei router.

Tipicamente Ethernet standard può arrivare fino a 1514 bytes ( con i Jumbo Frame si arriva circa ai 9KB se non erro e con i Super Jambo Frame a 64K).

Tolti i 14 bytes per l'header di Ethernet, rimangono 1500 bytes per IP, ed è tipicamente l'MTU che utilizzano i router.

Leva altri 40 bytes di header di IP e TCP e arrivi a 1460 bytes di dati utili.

Questo significa che nel tuo esempio il trasferimento di un file da 1MB richiederebbe:

1048576/1460 = 719 pacchetti circa

Nota bene: se decidi di leggere da una socket 4K alla volta, i meccanismi di buffering del sistema operativo potrebbero far abbassare il numero di system call necessarie.

Il punto è che stai usando un'api di cui se non ho capito male non si conoscono i dettagli implementativi.

misterx
16-03-2013, 10:29
Il punto è che stai usando un'api di cui se non ho capito male non si conoscono i dettagli implementativi.

è esattamente così. Mi sto ostinando ad usare tale componente già pronto solo perchè, essendo il mio progetto piuttosto complesso, tale componente è gia testato e mi fa comodo evitare problemi che di sicuro già esistono da qualche parte.
Per conoscenza, 8192 sono i byte che mi indica il compilatore quando chiamo la Size = Socket->ReceiveLength(); e quando invio da un client pacchetti di una certa dimensione cioè: il mio client casareccio legge da disco attraverso una fgets() ed ogni linea letta viene bufferizzata formando un bufferone che solo alla fine passa alla SendBuf() la quale crea pacchetti da 8192 byte.

ESSE-EFFE
16-03-2013, 12:55
Il punto è che stai usando un'api di cui se non ho capito male non si conoscono i dettagli implementativi.
A dire il vero tra documentazione ufficiale (http://docs.embarcadero.com/products/rad_studio/), libri, portali dedicati, forum, newsgroup e sorgenti VCL di informazioni se ne trovano a quintali.

misterx
16-03-2013, 16:16
A dire il vero tra documentazione ufficiale (http://docs.embarcadero.com/products/rad_studio/), libri, portali dedicati, forum, newsgroup e sorgenti VCL di informazioni se ne trovano a quintali.

se mi dici dove spiega quanto chiedo mi faresti un grandissimo favore, io non trovo nulla.

p.s.
questa ti sembra una spiegazione?

http://docwiki.embarcadero.com/Libraries/XE3/en/System.Win.ScktComp.TCustomWinSocket.ReceiveLength

WarDuck
16-03-2013, 17:30
Io consiglierei di partire da qua:

http://docwiki.embarcadero.com/Libraries/XE3/en/System.Win.ScktComp.TWinSocketStream


se mi dici dove spiega quanto chiedo mi faresti un grandissimo favore, io non trovo nulla.

p.s.
questa ti sembra una spiegazione?

http://docwiki.embarcadero.com/Libraries/XE3/en/System.Win.ScktComp.TCustomWinSocket.ReceiveLength

Call ReceiveLength to determine the amount of information to read over the socket connection in response to an asynchronous read notification.

Note: ReceiveLength is not guaranteed to be accurate for streaming socket connections.

misterx
16-03-2013, 17:54
Io consiglierei di partire da qua:

http://docwiki.embarcadero.com/Libraries/XE3/en/System.Win.ScktComp.TWinSocketStream




Call ReceiveLength to determine the amount of information to read over the socket connection in response to an asynchronous read notification.

Note: ReceiveLength is not guaranteed to be accurate for streaming socket connections.

letto grazie 1000, lo trovo però molto lacunoso; molte delle cose che osservo sperimentando non vengono minimamente spiegate e ti vedi costretto a fare miriadi di esperimenti, non che ciò mi turbi però vorrei ottenere alla fine un qualcosa di affidabile che riesco a controllare e non un qualcosa che funzionicchia chissà perchè :D
Andrà a finire che seguirò alla lettera il tuo consiglio, spostarmi sulle care e vecchi windows API, almeno vedi ciò che accade.

Cerca cerca ho trovato la guida Borland Builder per windows dove si dice che usare le socket in questo ambiente è banale, basta trascinare e settare qualche proprietà e tutto il resto è magia, mah :doh:

Se arrivo da qualche parte faccio sapere, almeno il prossimo non diventa matto come lo sto diventando io e ci scommetto che sono vittima di una banalità :)

grazie ancora per i link

misterx
16-03-2013, 21:42
trovandomi a lavorare col mio programma a livello applicativo, sotto ho TCP(IP che mi da le dovute garanzie, esiste una casistica che spiega a cosa possono essere dovuti eventuali perdite di pacchetti a livello applicativo?

Ho notato che nel piccolo client che ho scritto se aggiungo un ritardo di 20 ms nell'inoltro di pacchetti non ho perdite, però questo è un modo non corretto di operare in quanto mi baso sulla probabilità/fortuna che tutti i pacchetti arrivano entro 20 ms. Se dovessi avere un ritardo maggiore per una qualche ragione addio :muro:

misterx
17-03-2013, 09:59
edit