|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Senior Member
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3736
|
[C++] ancora problemi con le socket
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. |
![]() |
![]() |
![]() |
#2 | ||
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Socket e' un oggetto di una tua classe, o e' una classe di Borland?
Quote:
Quote:
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.
__________________
In God we trust; all others bring data |
||
![]() |
![]() |
![]() |
#3 | |
Senior Member
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3736
|
Quote:
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. |
|
![]() |
![]() |
![]() |
#4 |
Senior Member
Iscritto dal: May 2007
Città: Milano
Messaggi: 7103
|
Ma non è il max buffer che il server alloca..
Inviato dal mio Sony Xperia P
__________________
Apple Watch Ultra + iPhone 15 Pro Max + Rog Ally + Legion Go |
![]() |
![]() |
![]() |
#5 |
Senior Member
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3736
|
|
![]() |
![]() |
![]() |
#6 | |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Codice:
int Size = Socket->ReceiveLength(); 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. Quote:
__________________
In God we trust; all others bring data Ultima modifica di sottovento : 13-03-2013 alle 08:18. |
|
![]() |
![]() |
![]() |
#7 | ||
Senior Member
Iscritto dal: May 2001
Messaggi: 12847
|
Quote:
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. Quote:
Comunque il mio consiglio per capire meglio cosa stai facendo è affidarti alle librerie standard fornite con il sistema operativo. |
||
![]() |
![]() |
![]() |
#8 | |
Senior Member
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3736
|
Quote:
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); |
|
![]() |
![]() |
![]() |
#9 | |
Senior Member
Iscritto dal: May 2001
Messaggi: 12847
|
Quote:
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. |
|
![]() |
![]() |
![]() |
#10 | |
Senior Member
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3736
|
Quote:
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 |
|
![]() |
![]() |
![]() |
#11 | |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Quote:
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
__________________
In God we trust; all others bring data |
|
![]() |
![]() |
![]() |
#12 | |
Senior Member
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3736
|
Quote:
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" |
|
![]() |
![]() |
![]() |
#13 | |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Quote:
Quello che avevi detto prima (i.e. farsi spedire la lunghezza del file) non e' male, anzi....
__________________
In God we trust; all others bring data |
|
![]() |
![]() |
![]() |
#14 |
Senior Member
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3736
|
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.
|
![]() |
![]() |
![]() |
#15 | |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Quote:
Se proprio vuoi una libreria che ti semplifichi la vita, puoi comunque cercarne una su internet, usare qt, ....
__________________
In God we trust; all others bring data |
|
![]() |
![]() |
![]() |
#16 | |
Senior Member
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3736
|
Quote:
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? |
|
![]() |
![]() |
![]() |
#17 | |||
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Quote:
Quote:
Quote:
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
__________________
In God we trust; all others bring data |
|||
![]() |
![]() |
![]() |
#18 | |
Senior Member
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3736
|
Quote:
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 |
|
![]() |
![]() |
![]() |
#19 | |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Quote:
Io lo terrei, pero' ora sono curioso: hai per caso trovato qualche documentazione sulla rete? Qualcosa?
__________________
In God we trust; all others bring data |
|
![]() |
![]() |
![]() |
#20 | |
Senior Member
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3736
|
Quote:
Ultima modifica di misterx : 14-03-2013 alle 06:20. |
|
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 04:28.