View Full Version : C++ comunicazioni tramite UDP
Abdujaparov
13-10-2006, 09:03
Salve a tutti, dovrei realizzare due programmi che comunicano tramite UDP scambiandosi dati vari, tra i quali dei file di installazione di determinati programmi (è richiesto espressamente UDP anche per il trasferimento di programmi quindi non posso utilizzare TCP).
Per far comunicare client e server esistono delle particolari classi C++ per comunicare in UDP o ci sono solo le classiche socket stile C?
Grazie, ciao ciao.
trallallero
13-10-2006, 09:33
io ti posso solo dire che ci sono le classiche socket stile C.
se fai "man udp" lo vedi ...
Salve a tutti, dovrei realizzare due programmi che comunicano tramite UDP scambiandosi dati vari, tra i quali dei file di installazione di determinati programmi (è richiesto espressamente UDP anche per il trasferimento di programmi quindi non posso utilizzare TCP).
Per far comunicare client e server esistono delle particolari classi C++ per comunicare in UDP o ci sono solo le classiche socket stile C?
Grazie, ciao ciao.
Se stai programmando per Windows, o usi i classici socket (libreria <winsock2.h>, e crei un socket UDP), oppure ti affidi al framework .NET, che ha delle classi ad hoc per questo (un po' come java). Non so se le MFC (Microsoft Foundation Class, un layer aggiuntivo di librerie per programmare più facilmente in C++ per Windows) prevedono delle classi per semplificare l'uso dei socket, puoi documentarti a riguardo. Il C++ ANSI non prevede classi per i socket, il networking si appoggia (giustamente) a librerie fornite dal Sistema Operativo.
ilsensine
13-10-2006, 10:30
tra i quali dei file di installazione di determinati programmi (è richiesto espressamente UDP anche per il trasferimento di programmi quindi non posso utilizzare TCP)
Chi ha chiesto questa cosa non capisce un fico secco di reti. Il protocollo udp è inaffidabile, va bene per dati non critici (audio/video, interrogazioni dns ecc.) ma non per trasferimento di eseguibili. Alcuni file sistem di rete (nfs, forse lo stesso smb) usano udp, ma con attorno logiche complesse.
Vedrai che sarai costretto a implementare a mano dei controlli sui pacchetti, gestendo in particolare la perdita e richiesta di ritrasmissione di frame udp (e non cito gli altri problemi dell'udp, in quanto più rari e a volte solo teorici). Quello che fa il tcp, insomma.
So che esistono librerie che implementano lo stack tcp; la miglior cosa sarebbe usare una di queste librerie e utilizzare il socket udp come strato di trasporto.
Chi ha chiesto questa cosa non capisce un fico secco di reti. Il protocollo udp è inaffidabile, va bene per dati non critici (audio/video, interrogazioni dns ecc.) ma non per trasferimento di eseguibili. Alcuni file sistem di rete (nfs, forse lo stesso smb) usano udp, ma con attorno logiche complesse.
Vedrai che sarai costretto a implementare a mano dei controlli sui pacchetti, gestendo in particolare la perdita e richiesta di ritrasmissione di frame udp (e non cito gli altri problemi dell'udp, in quanto più rari e a volte solo teorici). Quello che fa il tcp, insomma.
Già...
So che esistono librerie che implementano lo stack tcp; la miglior cosa sarebbe usare una di queste librerie e utilizzare il socket udp come strato di trasporto.
Beh, per windows è winsock2... implementa gli strati dal 5 al 7 dello stack OSI (o più precisamente, si interpone tra il 4 e il 5, offrendo funzioni per trattare trasparentemente gli strati superiori), e con i raw socket ti permette di scendere fino a livello 2 (come dati contenuti nei pacchetti).
EDIT: mi pare che con la SP2 di Win XP i raw socket siano stati disabilitati...
Abdujaparov
13-10-2006, 13:14
Si devo lavorare su windows, quindi devo accollarmi i classici socket no?
So che tcp era la soluzione migliore, ma probabilmente questo udp è stato inserito per farmi saltare i nervi e non riuscire a consegnare nulla, purtroppo posso solo sopportare.
Dove posso trovare le informazioni per implementare UDP su TCP?
Grazie, ciao ciao.
BountyKiller
13-10-2006, 13:20
il pacchetto udp è molto più semplice di tcp, nel senso che hai molte meno infomazioni da inserire nel pacchetto.... quindi inizia con udp...se la tua applicazione deve funzionare solo su reti locali dovrebbe funzionare egregiamente, mentre se in futuro la vorrai utilizzare su reti più grandi dovrai probabilmente utilizzare tcp (come ti è già stato detto).
In sostanza la scelta di udp mi sembra dettata dal fatto che non hai molta esperienza e quindi ti hanno (giustamente) detto di "partire dalle cose semplici".
bye
Si devo lavorare su windows, quindi devo accollarmi i classici socket no?
So che tcp era la soluzione migliore, ma probabilmente questo udp è stato inserito per farmi saltare i nervi e non riuscire a consegnare nulla, purtroppo posso solo sopportare.
Dove posso trovare le informazioni per implementare UDP su TCP?
Grazie, ciao ciao.
Se vuoi fare un tunnel UDP over TCP, ti serve fare un "tunnel server", ovvero:
Il tuo programma si collega al tunnel server in UDP, il tunnel server usa TCP per trasmettere il pacchetto al tunnel server remoto, il quale lo riconverte in UDP e lo destina al programma remoto di destinazione. Il tunnel server può essere "inglobato" nel tuo programma ovviamente, con un doppio socket.
Puoi trovare un esempio in java (fatto per giocare a Quake3) che esplica il meccanismo. Puoi ricavare da lì il codice (oppure cercare su google per soluzioni in C).
EDIT: se non vuoi complicarti la vita con i tunnel, e ti è espressamente richiesto UDP, usa UDP con winsock2 (<winsock2.h>), sennò l'unica strada è il tunnel.
il pacchetto udp è molto più semplice di tcp, nel senso che hai molte meno infomazioni da inserire nel pacchetto.... quindi inizia con udp...se la tua applicazione deve funzionare solo su reti locali dovrebbe funzionare egregiamente, mentre se in futuro la vorrai utilizzare su reti più grandi dovrai probabilmente utilizzare tcp (come ti è già stato detto).
In sostanza la scelta di udp mi sembra dettata dal fatto che non hai molta esperienza e quindi ti hanno (giustamente) detto di "partire dalle cose semplici".
bye
Beh si parla di trasporto... Normalmente non si va ad intervenire direttamente con quel livello, bensì si crea il socket dicendogli di usare il trasporto TCP o UDP (o altri, dipende dall'implementazione dello stack di rete).
Il programmatore che usa l'API che implementa lo stack di rete non si preoccupa di come fisicamente sono trasportati i dati, bensì, nel caso di UDP, della corretta ricostruzione dei pacchetti alla destinazione (con TCP l'ordine dei pacchetti è garantito dal trasporto, in UDP no), mica devi andare a costruire il pachetto fisicamente :)
Non mi sembra che debba fare un tunnel UDP over TCP ;)
Deve semplicemente implementare un protocollo sicuro su UDP. Hai necessità di particolari prestazioni ? Inoltre il protocollo deve funzionare in modo asimmetrico ? Cioè A manda dati a B, ma B non manda dati ad A (se non quelli necessari al protocollo)...
Il problema principale dell'UDP è che i pacchetti che invii da A a B possono arrivare duplicati, fuori sequenza, alterati o possono non arrivare per niente...
In tal caso devi studiarti diverse cosine...
1) controllo di errore, credo che sia d'obbligo un CRC
2) controllo di flusso e controllo di sequenza
Prima cosa devi dimensionare il pacchetto UDP e definirne il formato.
Ad esempio:
Pacchetto inviato da A:
|NumeroDiSequenza(X bit)|Dati(max ~1200 bit)|CRC(16 bit)|
Pacchetto inviato da B in risposta ad un pacchetto di A (pacchetto detto di Acknowledgement):
|NumeroDiSequenza(X bit)|CRC(16 bit)|
Ed ha il significato: io B ho ricevuto il pacchetto identificato dal numero di sequenza...
Il CRC è calcolato sull'intero pacchetto CRC escluso...
Poi ti devi creare il protocollo di basso livello che ti crea in partica un canale affidabile fra A e B...
Questo è quello che deve fare A: si crea una buffer circolare in cui si vanno ad inserire i pacchetti (accompagnati dal timestamp di spedizione), se il buffer è pieno non si fa la spedizione.
Man mano che ricevi gli acknowledgement spunti un flag nell'elemento del buffer relativo al pacchetto di cui hai avuto la conferma di ricezione...se il pacchetto di cui hai avuto conferma è il primo allora fai avanzare il puntatore al primo elemento del buffer fino a quando non viene puntato un elemento che non ha ricevuto acknowledgement.
Per non avere problemi scegli la dimensione del buffer circolare molto minore del max numero di sequenza.
Se riceve un pacchetto con CRC errato lo scarta...se riceve un acknowledgement che ha già ricevuto o di un pacchetto che non è nel buffer lo scarta...
Ogni 300 ms fai scattare un timer che scorre tutti gli elementi del buffer che non hanno ricevuto acknowledgement, se la differenza fra il tempo attuale e il timestamp è maggiore di Y secondi (timeout) allora ritrasmetti il pacchetto e aggiorna il timestamp.
Dalla parte di B:
- ricevi un pacchetto con CRC errato, non fai niente e lo scarti
- ricevi un pacchetto con CRC giusto, invii il relativo pacchetto di acknoledgement (non conta se è duplicato, lo invii comunque)
- ricevi un pacchetto con CRC giusto e che non hai già ricevuto, lo metti da parte in una lista che devi mantenere ordinata
A questo punto ad un livello più alto del protocollo ti metti d'accordo sulla dimensione dei dati da trasmettere nelle varie sessioni di trasmissione... In pratica ti appoggi al pacchetto di basso livello che implementa una connessione sicura (si spera) e stabilisci i parametri della connessione...
Ad esempio, voglio inviare un file di dimensione 100KB e di nome "pippo.txt" a cui fai seguire il file.
E' rimasto un problema, dimensionare il timeout Y...per dimensionare il timeout devi fare una stima del tempo che passa tra l'invio dei dati e l'acknowledgement relativo...questo tempo è definito Round Trip Time (RTT).
La stima è presto fatta: stabilisci un RTT iniziale, che so 1 secondo. Ogni volta che ricevi un Acknowledgement fai la differenza fra il timestamp in cui l'ack è stato ricevuto e quello in cui è stato inviato. A questo punto fai na media "sbilanciata".
RTT_attuale = (RTT_attuale * 3 + (timestamp_ricezione - timestamp_invio)) / 4
timeout Y = 3 * RTT_attuale
Per il CRC c'è questo link: http://www.relisoft.com/Science/CrcMath.html
Abdujaparov
14-10-2006, 09:04
Grazie a tutti, cionci è colui che ha colto nel segno. L'applicazione deve funzionare in rete, tra molti host, il protocollo TCP non lo posso usare perchè mi è espressamente richiesto di utilizzare UDP qualunque cosa accada.
Esistono delle librerie già pronte che implementano CRC? Sono solo in C o sono scritte anche in C++ (con quelle belle classi che mi fanno tanta simpatia)?
Grazie, ciao ciao.
BountyKiller
14-10-2006, 09:55
evvabbè usando un'api è capace anche mia nonna e tutto diventa un banale esercizio di programmazione....
ma il tunneling udp over tcp che cosa c'entra?????
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.