|
|
|
|
Strumenti |
21-12-2011, 10:21 | #1 |
Senior Member
Iscritto dal: Oct 2004
Messaggi: 304
|
[C] dubbio send e recv su programma client-server
Salve cercherò di spiegare il mio dubbio.
Supponiamo di avere un programma organizzato in due file client.c e server.c . Nel client sono eseguite più send con lo stesso argomento socket, e tra una send e l'altra vi è altro codice. Nel server sono invece eseguite lo stesso numero di recv con lo stesso socket della send, e anche qui tra una recv e l'altra vi è altro codice. La domanda è questa: la "sincronizzazione" tra le varie send e recv è automatica? nel senso, sono sicuro che la seconda send del client si "sposerà" con la seconda recv del server? dopo una send il programma prosegue con l'esecuzione del codice? dopo la recv? vi possono essere dei malfunzionamenti dovuti al fatto, per esempio, che ci sia troppo codice (e quindi il programma "perda troppo tempo") tra una recv e l'altra (nel frattempo il client potrebbe essere andato molto avanti nell'esecuzione del suo codice!) Grazie |
21-12-2011, 10:24 | #2 |
Senior Member
Iscritto dal: Jan 2008
Messaggi: 8406
|
tralasciando i dettagli sul fatto che i socket di default sono blocking, c'è da notare che se il client fa send ( o viceversa ) non è detto che il server riceva proprio quel pacchetto
se c'è un altro client "malevolo" che invia pacchetti al server su quella porta? il server potrebbe ricevere questi ultimi in genere quando fai recv devi in qualche modo creare un loop, dove ricevi i dati, li verifichi e quelli non buoni li scarti |
21-12-2011, 10:27 | #3 | |
Senior Member
Iscritto dal: Oct 2004
Messaggi: 304
|
Quote:
Poi cosa significa che i socket di default sono blocking? |
|
21-12-2011, 13:44 | #4 | |
Senior Member
Iscritto dal: Jan 2008
Messaggi: 8406
|
Quote:
però il problema è che quel blocco di dati può essere stato mandato da qualcuno che non è il client previsto, ma magari un altro client, un programma disturbatore o qualsiasi altro soggetto in grado di mandare dati sulla rete |
|
21-12-2011, 13:50 | #5 | |
Senior Member
Iscritto dal: Oct 2004
Messaggi: 304
|
Quote:
vabbè ma per un programma a scopo didattico non ho di questi problemi giusto? e cmq la recv è blocking sempre e comunque, oppure solo se vi mettiamo l'opzione WAITALL? e poi il discorso nn mi torna molto...se la recv è nel server.c sarà questo programma che si blocca, ma il client continuerà a girare no? |
|
21-12-2011, 15:26 | #6 | |||
Senior Member
Iscritto dal: Jan 2008
Messaggi: 8406
|
Quote:
anni fa ho scritto un client e un server pxe e lì è normale avere client che interagiscono nello stesso momento con lo stesso server, il tutto in modalità connectionless per i socket connection oriented, il sistema gestisce la cosa automaticamente per esempio un normale server telnet non deve fare verifiche, un server dhcp deve eccome mi era venuto il dubbio perchè usi recv e send, in genere per i socket "normali", cioè quelli connection oriented, si usano read e write Quote:
normalmente la recv si blocca Quote:
la send manda i dati e basta e, a parte problemi nell'invio, viene eseguita velocissimamente Ultima modifica di pabloski : 21-12-2011 alle 15:30. |
|||
21-12-2011, 23:24 | #7 | ||||
Senior Member
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1816
|
Quote:
In sostanza: non farci affatto affidamento. Se devi sapere se quante recv devi effettuare, conta il numero di byte che ricevi e continua ad aspettare finche' hai tutti quelli che ti servono. Quote:
Quote:
Se intendi se il programma si ferma in attesa che l'altro capo faccia una recv, allora la risposta e' no, usualmente, si tratta solo di aspettare che i dati raggiungano il buffer di spedizione. Con qualche caveat, vedi sotto. Quote:
In un protocollo connectionless tipo UDP se il client continua a spedire e il server non fa le recv, ad un certo punto riempi il buffer disponibili lato server.Da qui in poi i pacchetti successivi verranno persi, finche' non verranno fatte un po' di recv per liberare spazio. Nel caso TCP e simili invece, una volta che il server ha finito il buffer comunica al client la cosa (e' un po' piu' complesso, ma rende l'idea). A questo punto lato client comincera' a riempirsi il buffer di spedizione. Una volta che si e' riempito del tutto, chiamate a send si bloccheranno e il programma continuera' solo quando il buffer si svuota un po'. A meno che tu non abbia impostato il socket in modalita' non bloccante, in tal caso la send invece che bloccarsi ritorna subito con un particolare codice di errore.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele |
||||
22-12-2011, 17:59 | #8 | |
Senior Member
Iscritto dal: Oct 2004
Messaggi: 304
|
Quote:
dunque sto cominciando a capirci qualcosa. Allora specifico intanto che utilizzo il protocollo TCP, e quando creo il socket gli passo come secondo parametro (parametro int type) SOCK_STREAM. Vediamo se riesco adesso a mettere in pratica quanto hai scritto, magari aiutami In pratica nella mia applicazione ho un file client.c, e quando lo eseguo devo immettere un comando, supponiamo send [nome_file] . Questo determinato comando deve prelevare il file nome_file e spedirlo al server, il quale lo salverà in una sua cartella locale. Ora io avevo pensato di fare così: quando nel client viene riconosciuto questo comando, invio al server una lettera (che fungerà diciamo da codice), facciamo il carattere S. Quindi nel client ad un certo punto scriverò una cosa del genere: Codice:
char cod_comando = 'S'; send (sd, (void*)&cod_comando, 1, 0); Codice:
recv(sock_des, &comando, 1, MSG_WAITALL); Quindi proseguendo metto (nel server) subito dopo la recv uno swith (comando), pertanto cosideriamo il caso case 'S'. Dunque ritornando al client, subito dopo la send metterei una cosa del genere: Codice:
int len = strlen (nome_file); send(sd, (char*)&len, sizeof(len), 0); send(sd, (char*)nome_file, strlen(nome_file), 0); send(sd, (char*)&info.st_size, 8, 0); //dico al server quanto è grosso il file che sto per inviare, assumendo che st_size di tipo off_t sia lungo 8 byte Nel server infatti nel case 'S' mettevo qualcosa del genere: Codice:
char send_temp[1024]; int lunghezza_nome; long lunghezza_file; recv(sock_des, (char*) &lunghezza_nome, 4, 0); recv(sock_des, send_temp, lunghezza_nome, 0); recv(sock_des, (char*) &lunghezza_file, 8, 0); //st_size è un long da 8 byte Grazie Ultima modifica di Eddie1985 : 22-12-2011 alle 18:09. |
|
22-12-2011, 22:37 | #9 |
Senior Member
Iscritto dal: Jul 2011
Messaggi: 381
|
ok, così di sicuro NON funzionerà mai se hai intenzione di avere più client.
Non funziona per il semplice fatto che, se hai più client, essi vanno a scrivere sulle stesse variabili del server. Devi utilizzare i semafori.
__________________
Concluso positivamente con: Kamzata, Ducati82, Arus, TheLastRemnant, ghost driver, alexbull1, DanieleRC5, XatiX |
22-12-2011, 23:07 | #10 |
Member
Iscritto dal: Jul 2011
Messaggi: 246
|
Non sono d'accordo, secondo me concettualmente può funzionare (apparte qualche svista nel codice ovvio). Se anche dovesse gestire tanti client, cosa che richiederebbe il multi-threading, nessuno interferisce con nessuno (se è questo il problema, come mi sembra di capire) perchè le socket TCP sono identificate da una quaterna di valori: porta sorgente, porta destinazione, ip sorgente, ip destinazione e quindi in una connessione le due "estremità" sono univocamente determinate una volta stabilita la connessione. Se nel client fai N send e nel server fai N recv secondo me non c'è dubbio che lo scambio dati sarà "sincronizzato". L'importante è che il server sappia che il primo dato è il tipo di comando, il secondo la lunghezza del file e via dicendo... Tutto il resto (multiplexing/demultiplexing delle connessioni) ci pensa il kernel... Non so se ho proprio centrato il bersaglio
|
22-12-2011, 23:52 | #11 | |
Senior Member
Iscritto dal: Oct 2004
Messaggi: 304
|
Quote:
|
|
23-12-2011, 00:56 | #12 | |
Senior Member
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1816
|
Quote:
La sincronizzazione la fai sui byte inviati. Tanti ne invii tanti ne devi ricevere. Ovviamente devi sapere lato server quanti byte devi ricevere. Per sapere questo puoi decidere di usare messaggi sempre della stessa dimensione, oppure di spedire per prima cosa la dimensione totale dei byte da leggere, oppure designare un carattere particolare come fine del messaggio. Spedire la dimensione del messaggio (o delle sue parti) e' secondo me la cosa piu' semplice da implementare. E' simile all'approccio che stai usando. - Invii il comando (1 char fisso) - Invii la dimensione della stringa col nome del file, oppure la stringa terminata da '\0'. Dall'altro lato leggi la stringa - Leggi ed invii la dimensione N in byte del file. La invii al server. - Leggi da disco e scrivi su socket N byte, che leggi dall'altra parte. Come vedi alla fine dell'operazione sono sincronizzato. Tanti byte ho scritto, tanti ho letto. Fine.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele |
|
23-12-2011, 01:02 | #13 | |
Senior Member
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1816
|
Quote:
Intanto lasciamo da parte il discorso di piu' client... questo lo risolvi a monte ed e' un problema ortogonale a quello in questione. Qui parliamo di una connessione su uno stream socket TCP. Per cui la connessione e' gia' stata effettuata, l'eventuale thread gia' avviato e non ci sono dubbi che i byte che il client manda arrivino a chi di dovere. Questo non toglie pero' che il numero di send e recv non e' necessariamente uguale. Quando hai un socket come TCP non c'e' alcun concetto di pacchetti, pezzi di byte distinti dagli altri etc. C'e' solo un flusso piu' o meno costante di byte. Quello che ottieni con la recv non e' altro che il contenuto del buffer di sistema. In condizioni ottimali (cioe' la recv e' li in attesa di dati e il sistema e' scarico) appena una send manda dei dati, questi mi arrivano nel buffer e mi vengono restituiti dalla recv. Ma se il sistema e' intasato ? Puo' succedere che ricevo due, tre o piu' pacchetti di fila e che questi si accumulino nel buffer. Quando finalmente avro' il tempo di leggere il socket, la recv probabilmente mi restituira tutti e tre i pacchetti contemporaneamente (sempre nell'ipotesi che cerco di leggere tutto in un colpo eh). Ottengo tre send e una recv.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele |
|
23-12-2011, 09:03 | #14 | |
Member
Iscritto dal: Jul 2011
Messaggi: 246
|
Quote:
Ultima modifica di Mettiu_ : 23-12-2011 alle 09:13. |
|
23-12-2011, 09:50 | #15 | ||
Senior Member
Iscritto dal: Oct 2004
Messaggi: 304
|
mmm dunque purtroppo continuo ad essere confuso .
Cerchiamo di fare chiarezza! Quote:
E' esattamente come hai scritto! Quote:
Ma io continuo a non capire se le problematiche che cercavo di spiegare all'inizio del thread ci siano oppure no! Dunque dopo che ho fatto le send dal lato client, i dati saranno o nelle variabili o comunque in un buffer, e prima o poi verranno presi dalla recv del lato server? Ma intanto il lato client, dopo aver eseguito le send, va avanti con il codice, e chi mi garantisce che le recv sul lato server siano già state effettuate???? |
||
23-12-2011, 10:07 | #16 |
Member
Iscritto dal: Jul 2011
Messaggi: 246
|
Si ma qui i problemi sono due:
1) Sincronizzazione tra server e client, cioè quello che uno invia l'altro lo legge. E abbiamo detto di si, se gestisci opportunamente il flusso e la sequenza di "campi" che invii dall'altra parte si, puoi fare in modo che client e server siano sempre sincronizzati (dipende solo da te e secondo me stavi facendo bene). 2) Il client invia un dato e vuole accertarsi, prima di proseguire, che il server l'abbia ricevuto. Questo è un altro problema. Se vuoi essere sicuro della ricezione dovresti prevedere ACK espliciti che, secondo me, non servono a niente nel tuo caso: il client prosegue l'esecuzione, prima o poi aspetterà risposte dal server e si metterà in ricezione con la recv fino a quando il server risponde. Se l'applicazione è fatta bene queste risposte arriveranno, devi prevedere che client e server non siano mai ENTRAMBI in recv() altrimenti ottieni un deadlock... |
23-12-2011, 10:15 | #17 | |
Senior Member
Iscritto dal: Oct 2004
Messaggi: 304
|
Quote:
Mi rimetto a lavoro così in caso vi richiedo aiuto |
|
23-12-2011, 10:54 | #18 |
Senior Member
Iscritto dal: Jul 2011
Messaggi: 381
|
Attenzione a non confondere il descrittore di socket, diverso per ogni connessione, con il fatto che le recv vanno a scrivere sulle stesse variabili del server.
Per quel che riguarda la consistenza dei dati, essa è implicita nel protocollo TCP. E' raro dover implementare un controllo con degli ACK se non in alcuni casi particolari. Per esempio l'invio di un grosso buffer con parecchie send.
__________________
Concluso positivamente con: Kamzata, Ducati82, Arus, TheLastRemnant, ghost driver, alexbull1, DanieleRC5, XatiX Ultima modifica di starfred : 23-12-2011 alle 10:57. |
23-12-2011, 11:37 | #19 | ||
Senior Member
Iscritto dal: Oct 2004
Messaggi: 304
|
Quote:
Quote:
|
||
23-12-2011, 12:05 | #20 |
Senior Member
Iscritto dal: Jul 2011
Messaggi: 381
|
Io immagino che tu stia in un sistema multithread, nel quale ogni thread gestisce un socket descriptor, cioè che ogni thread gestisce una connessione con un client. Se qualche thread fa riferimento a variabili globali, come nel 99% dei casi avviene, allora devi implementare un meccanismo di mutua esclusione per tali variabili.
Spero di esser stato chiaro. Ciao
__________________
Concluso positivamente con: Kamzata, Ducati82, Arus, TheLastRemnant, ghost driver, alexbull1, DanieleRC5, XatiX |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 22:39.