Torna indietro   Hardware Upgrade Forum > Software > Programmazione

HP Elitebook Ultra G1i 14 è il notebook compatto, potente e robusto
HP Elitebook Ultra G1i 14 è il notebook compatto, potente e robusto
Pensato per il professionista sempre in movimento, HP Elitebook Ultra G1i 14 abbina una piattaforma Intel Core Ultra 7 ad una costruzione robusta, riuscendo a mantenere un peso contenuto e una facile trasportabilità. Ottime prestazioni per gli ambiti di produttività personale con un'autonomia lontano dalla presa di corrente che permette di lavorare per tutta la giornata
Microsoft Surface Pro 12 è il 2 in 1 più compatto e silenzioso
Microsoft Surface Pro 12 è il 2 in 1 più compatto e silenzioso
Basato su piattaforma Qualcomm Snapdragon X Plus a 8 core, il nuovo Microsoft Surface Pro 12 è un notebook 2 in 1 molto compatto che punta sulla facilità di trasporto, sulla flessibilità d'uso nelle differenti configurazioni, sul funzionamento senza ventola e sull'ampia autonomia lontano dalla presa di corrente
Recensione REDMAGIC Astra Gaming Tablet: che spettacolo di tablet!
Recensione REDMAGIC Astra Gaming Tablet: che spettacolo di tablet!
Il REDMAGIC Astra Gaming Tablet rappresenta una rivoluzione nel gaming portatile, combinando un display OLED da 9,06 pollici a 165Hz con il potente Snapdragon 8 Elite e un innovativo sistema di raffreddamento Liquid Metal 2.0 in un form factor compatto da 370 grammi. Si posiziona come il tablet gaming più completo della categoria, offrendo un'esperienza di gioco senza compromessi in mobilità.
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 01-07-2014, 21:04   #1
aeroxr1
Senior Member
 
Iscritto dal: Mar 2006
Messaggi: 2056
[c] consiglio su app socket :)

Ciao,
devo fare una semplice applicazione scritta in C modalità client-server su debian.

Le comunicazioni dovranno essere cliente - server usando tcp socket
e in uno step successivo client - client attraverso udp socket usando i dati presi dal server.

Il dubbio ora ce l'ho sulla comunicazione tra client e server.

In pratica il progetto mi richiede che prima di ogni invio di dati attraverso la socket tcp comunichi il numero di byte che sto inviando in maniera che il ricevente sappia quanti byte debba ricevere.

Server monoprocesso con la select() che individua la socket con i dati.

Il client invia il proprio username al server e dopo l'accettazione dal server (il quale andrà a creare una struttura apposita per ogni client) potrà inviare vari comandi che il server deve interpretare.

Dopo questa mega introduzione vi spiego il mio dubbio :
cosa potrei inventarmi per far si che il server discrimini tra i messaggi che gli arrivano per comunicare la dimensione in byte del msg successivo e il messaggio contenenti i contenuti veri e propri ?



Una variabile che identifica lo stato di ogni client ?
aeroxr1 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 07:56   #2
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Puoi realizzare una macchina a stati come avevi immaginato, oppure puoi cablare due read in sequenza, la prima lettura viene convertita in numero e il valore ottenuto viene utilizzato per dalla seconda per leggere il numero di byte corretto.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 09:05   #3
aeroxr1
Senior Member
 
Iscritto dal: Mar 2006
Messaggi: 2056
Quote:
Originariamente inviato da Daniels118 Guarda i messaggi
Puoi realizzare una macchina a stati come avevi immaginato, oppure puoi cablare due read in sequenza, la prima lettura viene convertita in numero e il valore ottenuto viene utilizzato per dalla seconda per leggere il numero di byte corretto.
Inizialmente volevo fare con il secondo metodo da te detto,facendo così ho un dubbio però:
-> client A invia i dati al Server
-> una volta finita la prima read da parte del server il controllo mi torna alla select
-> la select controlla i descrittori
-> trova che il descrittore della socket del client A ha dei dati
-> faccio la recv , ma a questo punto arriva il dubbio: come faccio a sapere se devo eseguire la prima recv o la seconda se non mi sono segnato da nessuna parte che la prima recv è già stata fatta ?

Grazie mille per l'aiuto che mi state dando
aeroxr1 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 10:54   #4
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
No aspetta, se cabli le due read di seguito devi per forza utilizzare un thread per ogni connessione, altrimenti rischi di far bloccare l'intero server.
Per gestire tutto con un unico thread devi necessariamente utilizzare una variabile di stato per ogni connessione.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 11:31   #5
aeroxr1
Senior Member
 
Iscritto dal: Mar 2006
Messaggi: 2056
Quote:
Originariamente inviato da Daniels118 Guarda i messaggi
No aspetta, se cabli le due read di seguito devi per forza utilizzare un thread per ogni connessione, altrimenti rischi di far bloccare l'intero server.
Per gestire tutto con un unico thread devi necessariamente utilizzare una variabile di stato per ogni connessione.
Eh è quello che pensavo , siccome le specifiche vogliono un monoprocesso monothread , quindi vado di select e variabili di stato.
aeroxr1 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 11:43   #6
Oceans11
Senior Member
 
L'Avatar di Oceans11
 
Iscritto dal: Sep 2005
Città: Torino
Messaggi: 606
Che il server deve poter gestire più client contemporaneamente è richiesto dalle specifiche?
In caso contrario non vedo perché utilizzare la select, basta affidarsi alla coda delle connessioni in attesa che tiene il server.
Poi riflettevo anche sul significato di 'prima' nella frase
Quote:
prima di ogni invio di dati attraverso la socket tcp comunichi il numero di byte che sto inviando in maniera che il ricevente sappia quanti byte debba ricevere.
Siccome non è vero che ad ogni send corrisponde un pacchetto, prima lo interpreterei come appena prima dei dati. Esempio:
Codice:
5hello
Così lato ricevente dovrai leggere un int e poi un array di char lungo quanto indicato dall'intero.
Occhio al terminatore di stringa e all'endianess degli interi (usa ntohl e htonl)
__________________
"Se proprio dovete piratare un prodotto, preferiamo che sia il nostro piuttosto che quello di qualcun altro." [Jeff Raikes]
"Pirating software? Choose Microsoft!"
Oceans11 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 12:28   #7
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Nulla di più vero di quanto dice Oceans11.
Suggerirei di convertire il numero che rappresenta la lunghezza del dato in una stringa di lunghezza fissa, per esempio int 5 diventa char[4] "0005", in questo modo la lettura diventa più semplice (leggi sempre 4 byte fissi) e risolvi il problema dell'endianess.

PS. dovresti inoltre implementare una logica tri-stato (in attesa, inizio lettura, completamento lettura), poiché non è detto che con una sola read ricevi tutti gli n byte previsti; non dare inoltre per scontato che i dati arrivino tutti insieme mettendo la read in loop, potresti bloccare tutto.

Ultima modifica di Daniels118 : 02-07-2014 alle 12:34.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 13:56   #8
aeroxr1
Senior Member
 
Iscritto dal: Mar 2006
Messaggi: 2056
Intanto grazie per le risposte Siete gentilissimi
in sostanza voi fareste una cosa del genere (ditemi se ho capito bene) :

client:

char usernameC[250];
printf("Inserisci il tuo nome: ");
scanf("%s",usernameC);
length=strlen(usernameC);
(non capisco il problema dell'endianess, tanto essendo una grandezza interpretata dall'host non posso lasciarla direttamente in formato host ? senza usare htonl e dopo viceversa ? )
poi con le funzioni per le stringhe collegarci lo usernameC in una cosa del genere (pacchetto=0010usenameC)

send(sd,&pacchetto,sizeof(pacchetto),0);

Il problema lato client è quando faccio la recv che allora devo aver capito male come funziona.. In pratica questa va a leggere dal buffer del socket giusto ? e qui ci sarà 0010usernameC , io mi prendo i primi 4 byte leggo quanti byte devo ricevere ancora e faccio la recv dello usernameC con la lunghezza presa precedentemente ?

In questa maniera in effetti sarebbe sempre chiaro quanti byte devo ricevere ogni volta . Ho capito bene ?

(chiaramente ci devono essere le gestioni di ricezione e invio di un numero minore di pacchetti quindi ci sarà da reinviare e o ricevere la restante parte )
aeroxr1 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 14:49   #9
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Le funzioni ntohl e htonl sono necessarie se vuoi trasmettere il numero in formato binario, perché il client e il server potrebbero avere processori con endianess diversa ed interpretare quindi il valore in modo diverso. Al limite i compilatori per le due architetture potrebbero avere addirittura una dimensione diversa per lo stesso tipo di dato (int o long).
Convertire il numero in stringa di lunghezza fissa produce esattamente lo stesso effetto, cambia solo il modo di rappresentazione.
Con il formato binario ovviamente riesci a risparmiare qualche byte.

Per il client puoi fare le due recv di seguito, tanto non devi servire richieste in parallelo.

Ultima modifica di Daniels118 : 02-07-2014 alle 14:51.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 15:09   #10
aeroxr1
Senior Member
 
Iscritto dal: Mar 2006
Messaggi: 2056
Quote:
Originariamente inviato da Daniels118 Guarda i messaggi
Le funzioni ntohl e htonl sono necessarie se vuoi trasmettere il numero in formato binario, perché il client e il server potrebbero avere processori con endianess diversa ed interpretare quindi il valore in modo diverso. Al limite i compilatori per le due architetture potrebbero avere addirittura una dimensione diversa per lo stesso tipo di dato (int o long).
Convertire il numero in stringa di lunghezza fissa produce esattamente lo stesso effetto, cambia solo il modo di rappresentazione.
Con il formato binario ovviamente riesci a risparmiare qualche byte.

Per il client puoi fare le due recv di seguito, tanto non devi servire richieste in parallelo.
Ah ho capito , in effetti io ragionavo pensando allo stesso compilatore stesso sistema operativo su entrambe le macchine

Nelle specifiche ho l'obbligo di utilizzo della select() per accettare nuove connessioni.

E' questa specifica che mi preoccupa :
"client e server si scambiano dei dati tramite socket TCP. Prima che inizi ogni scambio è necessario che il ricevente sappia quanti byte deve leggere dal socket. Non è ammesso che vengano inviati su socket numeri arbitrari di byte."

Ho paura di non rispettarla, ma ragionandoci mi sembra che la maniera di inviare in un unico pacchetto tutti i dati dimensione+contenuto rispetti in pieno le specifiche Chiederò ! Intanto provo facendo così

Una domanda sulla recv, lei legge dal buffer del socket fino a len giusto ? quindi in teoria mi basta leggere fino a len=4 (considerando 4 byte per le dimensioni) e dopo leggere il valore della dimensione che è lì riportato impostare la nuova dim di len e rifare la recv che andrà a leggere i restanti byte del buffer fino a len . La teoria che so è giusta o c'è qualche pecca ?

CHiaramente devo gestire il caso in cui send non invii tutti gli n byte e stessa cosa recv non legge tutti gli n byte .
In quel caso devo andare di ritrasmissione ?
aeroxr1 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 15:31   #11
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Con le connessioni TCP l'invio dei dati dovrebbe riuscire sempre (a meno di problemi di connessione), il sistema si preoccupa di spezzare il buffer in più pacchetti se necessario, l'unica operazione non sicura è la ricezione, poiché non è garantito che un messaggio diviso su due pacchetti arrivi tutto in un tempo così breve da consentirne il recupero con un'unica recv (sempre ammesso che il secondo pacchetto arrivi veramente ).
Anche la lettura dei primi 4 byte andrebbe bufferizzata, immagina questa situazione con dei pacchetti da 512 byte:
1) invio un messaggio da 506 byte + 4 per la lunghezza, ma il pacchetto non parte perché il buffer ha ancora spazio per 2 byte e il sistema aspetta ancora un po' per vedere se si riempie;
2) subito dopo invio un messaggio di 100 byte + 4 per la lunghezza;
3) il sistema bufferizza i dati e li divide in due pacchetti, il primo contiene 4+506+2 byte, il secondo ne contiene 2+100;
4) il client riceve il primo pacchetto e ne legge 4 byte, vede che il dato è lungo 506 byte e li legge;
5) il buffer contiene ancora 2 byte, quindi il client prova a leggere 4 byte, ma ne ottiene solo due perché il secondo pacchetto non è ancora arrivato, quindi interpreta male la lunghezza del dato... da qui in poi si scatena l'inferno
Le connessioni UDP non le ho mai utilizzate, ma credo che per esse devi essere tu a spezzare i dati in buffer di lunghezza opportuna.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 16:04   #12
aeroxr1
Senior Member
 
Iscritto dal: Mar 2006
Messaggi: 2056
infatti sono qui che mi sto scervellando per poter capire come fare il tutto senza avere problemi nella ricezione del dato contenente la lunghezza del successivo pacchetto in maniera da dimensionare il buffer nella maniera più opportuna.

Vabbè che questo è un progetto per scopo didattico, e quindi non dovrà trasferire grossi dati , però le cose mi piace impararle ammodino

fare la send in un unico colpo contenente tutti i dati o due send con buffer più piccolo ?

Ora come ora pensavo di fare la recv di 4 byte o di un intero per la dimensione e se questa riceveva meno dati abortire il tentativo di connessione e via chiudendo il server . Per scopo didattico può andare, dal punto di vista reale sarebbe una magagna non da poco.
aeroxr1 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 17:18   #13
Oceans11
Senior Member
 
L'Avatar di Oceans11
 
Iscritto dal: Sep 2005
Città: Torino
Messaggi: 606
Quote:
Originariamente inviato da aeroxr1
infatti sono qui che mi sto scervellando per poter capire come fare il tutto senza avere problemi nella ricezione del dato contenente la lunghezza del successivo pacchetto in maniera da dimensionare il buffer nella maniera più opportuna.
Aspè, forse sbagli approccio. Tu non sai a priori (prima che ti arriva il pacchetto) quanto è lungo il payload tcp. Quindi il buffer lo fai grosso a piacere.
Una cosa tipo:
Codice:
#define SIZE 256
[...]
char buff[SIZE];
while (1) {
    int brecv = recv(s, buff, SIZE, 0);
    if (brecv < 0) {
        // gestisci l'errore, chiudi tutto e liberi memoria
    }
    if (brecv == 0) {
        // Nessun messaggio nel canale e il peer ha fatto shutdown()
        break;
    }
    // qui consumi i brecv bytes letti
}
Come vedi il ciclo è infinito, o meglio, la recv si accorge se la controparte ha finito e ti restituisce 0, quindi esci con il break.

Quote:
Originariamente inviato da aeroxr1
fare la send in un unico colpo contenente tutti i dati o due send con buffer più piccolo ?
direi un'unica send con un buffer che contiene sia la lunghezza (restante) che i dati veri e propri. Ma non sto parlando di efficienza.
__________________
"Se proprio dovete piratare un prodotto, preferiamo che sia il nostro piuttosto che quello di qualcun altro." [Jeff Raikes]
"Pirating software? Choose Microsoft!"
Oceans11 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 17:42   #14
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Quote:
[..] Come vedi il ciclo è infinito, o meglio, la recv si accorge se la controparte ha finito e ti restituisce 0, quindi esci con il break. [..]
Preciso che questo codice ovviamente va bene per un client o un server multithread, mentre per un server monothread bisogna inserire il discorso della select e degli stati.
Quote:
fare la send in un unico colpo contenente tutti i dati o due send con buffer più piccolo ?
La mia opinione è che è del tutto indifferente, il risultato potrebbe essere avere uno o due pacchetti in entrambi i casi, dipende dall'implementazione dei vari strati software sottostanti.

Il mio parere è che dovresti implementare una routine che bufferizza i dati letti, quindi fai l'elaborazione solo se i dati sono effettivamente sufficienti.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 18:01   #15
aeroxr1
Senior Member
 
Iscritto dal: Mar 2006
Messaggi: 2056
Quote:
Originariamente inviato da Oceans11 Guarda i messaggi
Aspè, forse sbagli approccio. Tu non sai a priori (prima che ti arriva il pacchetto) quanto è lungo il payload tcp. Quindi il buffer lo fai grosso a piacere.
Una cosa tipo:
Codice:
#define SIZE 256
[...]
char buff[SIZE];
while (1) {
    int brecv = recv(s, buff, SIZE, 0);
    if (brecv < 0) {
        // gestisci l'errore, chiudi tutto e liberi memoria
    }
    if (brecv == 0) {
        // Nessun messaggio nel canale e il peer ha fatto shutdown()
        break;
    }
    // qui consumi i brecv bytes letti
}
Come vedi il ciclo è infinito, o meglio, la recv si accorge se la controparte ha finito e ti restituisce 0, quindi esci con il break.



direi un'unica send con un buffer che contiene sia la lunghezza (restante) che i dati veri e propri. Ma non sto parlando di efficienza.
si si , il problema è che se recv riceve meno di len byte dovrò gestire l'errore , ed è li che mi si crea il problema di come fare .

Il prototipo di pacchetto che creerò sarà questa :

|header 2byte contenente la lunghezza del campo dati|comando 1byte|campo dati variabile|

supponiamo che la client invii un pacchetto così fatto :

|DATA LENGHT 25byte|comando|------------DATA----------------|

Cioè io ricevo con la recv e se questa mi riceve meno di due byte non avrò ricevuto per intero nemmeno l'header e dovrò gestire l'errore , stessa cosa se ricevo meno di 28 byte non ho ricevuto l'intero messaggio.
Questo errori non so come gestirli almeno per ora

Pensavo ad inviare un pacchetto del genere in maniera che con il campo "comando" possa evitare di fare la macchina a stati che può risultare noiosa e andrò ad inviare comandi del tipo :
- username
- porta
- chi è connesso
stilizzate in un semplice byte.

Non ho ben capito se mi consigli di fare una unica recv con una lenght dell'intero buffer [a questo punto però violo la specifica del progetto ] o due recv consecutive una con 3 byte cioè la lunghezza fissa [header|comando] e una relativa alla lunghezza variabile [DATA]
Il secondo metodo non so nemmeno se sia fattibile o meno

Per eliminare il problema della ricezione frammentata devo fare come dice @Daniels118 una lettura bufferizzata .
E come impostare le recv

Il problema mi deriva dal fatto che teoricamente pensavo che se la send inviava x byte la recv ricevesse fino a len=x byte , in realtà la recv può anche leggere n < x byte e poi i restanti rimangono disponibili per una futura recv .
In pratica la recv serve a leggere il buffer della socket . Giusto ?

Ultima modifica di aeroxr1 : 02-07-2014 alle 20:49.
aeroxr1 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 19:25   #16
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Esatto! Tieni presente però che non è detto che la seconda parte dei dati sia subito disponibile, per cui fare due recv consecutive senza gli opportuni controlli è inutile.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 20:53   #17
aeroxr1
Senior Member
 
Iscritto dal: Mar 2006
Messaggi: 2056
Quote:
Originariamente inviato da Daniels118 Guarda i messaggi
Esatto! Tieni presente però che non è detto che la seconda parte dei dati sia subito disponibile, per cui fare due recv consecutive senza gli opportuni controlli è inutile.
Ma anche la prima potrebbe avere questo problema giusto ? ( per capire se ho capito Ihih)

Pensavo che TCP del sender segmentasse i pezzetti, ma poi il receiver ricomponesse il tutto prima di darli alla socket . Non è così ? :/

Inviato dal mio Galaxy Nexus utilizzando Tapatalk
aeroxr1 è offline   Rispondi citando il messaggio o parte di esso
Old 02-07-2014, 21:06   #18
WarDuck
Senior Member
 
L'Avatar di WarDuck
 
Iscritto dal: May 2001
Messaggi: 12814
Usa e poi scorda TCP. TCP ti assicura che il ricevente legga tutto come uno stream di bytes. Quando chiedi di leggere 4 bytes dalla socket, la funzione non ritorna finché non ha letto 4 bytes (più o meno, vedi meglio le eccezioni, esempio l'altro lato chiude la connessione).

Comunque ti conviene strutturare tutto in messaggi aventi un header del tipo:

Codice:
struct message_header
{
    uint32_t length;
    char variable_message[0]; // nn ricordo ma dovrebbe funzionare su C99
};
Quando allochi la memoria dinamicamente ti preoccupi di allocarne per

Codice:
sizeof(struct message_header) + lunghezza messaggio
Così facendo allochi lo spazio per la struttura header e per il messaggio.

A quel punto casti il puntatore restituito dalla malloc con uno struct message_header e puoi impostare sia length che accedere direttamente al messaggio (in questo esempio è solo un array variabile di bytes).

All'invio invierai tutto il contenuto della struttura puntata.

Alla ricezione leggerai dapprima sizeof(struct message), e poi da lì continuerai a leggere per quanti bytes ti dice il campo length...

Ultima modifica di WarDuck : 02-07-2014 alle 21:09.
WarDuck è offline   Rispondi citando il messaggio o parte di esso
Old 03-07-2014, 00:08   #19
aeroxr1
Senior Member
 
Iscritto dal: Mar 2006
Messaggi: 2056
Quote:
Originariamente inviato da WarDuck Guarda i messaggi
Usa e poi scorda TCP. TCP ti assicura che il ricevente legga tutto come uno stream di bytes. Quando chiedi di leggere 4 bytes dalla socket, la funzione non ritorna finché non ha letto 4 bytes (più o meno, vedi meglio le eccezioni, esempio l'altro lato chiude la connessione).
Eh proprio per quello non capisco a cosa serva preoccuparmi del buffer , se tanto la recv aspetta fino a che non ho letto i 4byte e si blocca se il buffer è vuoto .
L'unico problema sarebbe se il buffer non è stato riempito per quanti byte mi aspettavo a quel punto la mia recv mi riporterà i byte letti che saranno in numero minore a quelli che mi aspettavo.
Per gestire questo problema potrei mettere un buffer che riempio mano a mano con la recv. Ma non mi riesce capire il , perchè ciò sia necessario.

Quote:
Originariamente inviato da WarDuck Guarda i messaggi
Comunque ti conviene strutturare tutto in messaggi aventi un header del tipo:

Codice:
struct message_header
{
    uint32_t length;
    char variable_message[0]; // nn ricordo ma dovrebbe funzionare su C99
};
Quando allochi la memoria dinamicamente ti preoccupi di allocarne per

Codice:
sizeof(struct message_header) + lunghezza messaggio
Così facendo allochi lo spazio per la struttura header e per il messaggio.

A quel punto casti il puntatore restituito dalla malloc con uno struct message_header e puoi impostare sia length che accedere direttamente al messaggio (in questo esempio è solo un array variabile di bytes).

All'invio invierai tutto il contenuto della struttura puntata.

Alla ricezione leggerai dapprima sizeof(struct message), e poi da lì continuerai a leggere per quanti bytes ti dice il campo length...
Non ci avevo pensato a creare una struttura e poi inviare quella pezzo per pezzo, pensavo ad una cosa più da newbie tipo un buffer di char con un byte per dimensione , 1 byte per il comando , restante per il campo dati.

Devo capire come inviare una struttura
E poi devo capire un paio di chicche del codice che hai scritto
Dichiarando :
Codice:
"char variable_message[0];"
se io dopo voglio allocare una stringa come dovrei fare ? Facendo così alloco dinamicamente il vettore ? Cercando su internet non avevo mai trovato questa soluzione
L'ho provata ma dipende dove la metto e mi funziona in altri posti no, ora domani la provo meglio
[ mi do una letta qui : http://stackoverflow.com/questions/9...e-array-in-c-c ]

Grazie !!!

Ultima modifica di aeroxr1 : 03-07-2014 alle 00:33.
aeroxr1 è offline   Rispondi citando il messaggio o parte di esso
Old 03-07-2014, 07:48   #20
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Quote:
Originariamente inviato da aeroxr1 Guarda i messaggi
Ma anche la prima potrebbe avere questo problema giusto ? ( per capire se ho capito Ihih)

Pensavo che TCP del sender segmentasse i pezzetti, ma poi il receiver ricomponesse il tutto prima di darli alla socket . Non è così ? :/

Inviato dal mio Galaxy Nexus utilizzando Tapatalk
Come ha detto WarDuck, il protocollo TCP ti assicura che i dati arrivino tutti (a meno che non cada la connessione) e nell'ordine corretto, ma non garantisce nulla riguardo alla loro atomicità. La parte più piccola che sei sicuro di ricevere è il byte, inviare anche solo due byte in sequenza (anche utilizzando un'unica send) non garantisce che con un'unica recv li riceverai entrambi.

Nota a margine: di solito il sistema operativo fa automaticamente il flush del buffer anche se non è pieno se dopo un po' di tempo non gli arrivano dati, per cui se il protocollo applicativo è basato su una comunicazione messaggio/risposta (quindi la parte non manda mai due messaggi di seguito senza prima aver ricevuto risposta) e la lunghezza del messaggio non supera la dimensione del pacchetto, allora il messaggio arriverà in un unico pacchetto e senza dati eccedenti, e sarà possibile leggerlo con un'unica recv. Questo approccio naturalmente si basa sulla validità delle condizioni elencate, se anche una sola di esse non è soddisfatta si ottengono comportamenti inaspettati. Per quanto riguarda l'autoflush non bisogna commettere l'errore di pensare di utilizzare fflush, perché questo comando agisce solo sui buffer delle librerie del c e non su quelli di sistema. Anche impostare TCP_NODELAY non è sufficiente, perché c'è un ulteriore meccanismo di caching dei buffer legato all'acknowledgement... insomma, l'unico modo certo per far funzionare le cose sempre e comunque è quello di scrivere uno strato software che accumuli i dati fino alla lunghezza desiderata prima di leggerli.
Codice:
struct message_header
{
    uint32_t length;
    char variable_message[0]; // nn ricordo ma dovrebbe funzionare su C99
};
In pratica inserisci nella struttura un campo che il compilatore interpreta come un array di char (attenzione, un array in-place, non un puntatore ad un array posizionato chissà dove), ma non ne definisci la lunghezza, poi a runtime allochi la struttura con dello spazio eccedente ed accedi al campo sforando oltre la dimensione teorica (0).
Se da qualche errore di compilazione si può tranquillamente definire l'array di lunghezza 1 e poi ricordarsi di allocare un byte in meno (ma anche se ci dimentichiamo non satureremo la memoria per un solo byte).
Il problema di questo metodo è che mandando quella struct sul socket non consideri eventuali differenze di endianess tra client e server. Personalmente opterei per le due send, non ci vedo nulla di male.
Quote:
L'unico problema sarebbe se il buffer non è stato riempito per quanti byte mi aspettavo a quel punto la mia recv mi riporterà i byte letti che saranno in numero minore a quelli che mi aspettavo.
Esatto, perché recv legge fino a n byte, ma anche se ce n'è uno solo lo legge lo stesso.
Quote:
Devo capire come inviare una struttura
La variabile che rappresenta la tua struttura non è altro che il puntatore restituito da malloc, basta che ne fai il cast a void* quando lo passi a send, tuttavia, come ho scritto prima, questo metodo non è l'ideale (a meno che non sei sicuro che tutte le piattaforme coinvolte abbiano la stessa endianess).
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


HP Elitebook Ultra G1i 14 è il notebook compatto, potente e robusto HP Elitebook Ultra G1i 14 è il notebook c...
Microsoft Surface Pro 12 è il 2 in 1 più compatto e silenzioso Microsoft Surface Pro 12 è il 2 in 1 pi&u...
Recensione REDMAGIC Astra Gaming Tablet: che spettacolo di tablet! Recensione REDMAGIC Astra Gaming Tablet: che spe...
Dopo un mese, e 50 foto, cosa abbiamo capito della nuova Nintendo Switch 2 Dopo un mese, e 50 foto, cosa abbiamo capito del...
Gigabyte Aero X16 Copilot+ PC: tanta potenza non solo per l'IA Gigabyte Aero X16 Copilot+ PC: tanta potenza non...
TV 4K Hisense a partire da 259€: modelli...
Carica di tutto, anche i MacBook, ha 7 p...
Lenovo Legion Go 2 mostrata in un video:...
iOS 26 Beta 4, torna il Liquid Glass! Ec...
Degrado batteria, ottime notizie anche p...
Un hard disk esterno Seagate da 20TB a 3...
GeForce RTX 5080, 5060 Ti e Radeon RX 90...
Sconti oggi sugli SSD Orico PCIe Gen.4 d...
Prezzo crollato per le Samsung Galaxy Bu...
MetaMask, bug nel wallet crypto: distrug...
Motorola edge 50 Neo 12/512GB o edge 60 ...
Dick Pic addio? L'AI di Flirtini insegna...
WhoFi: riconoscimento biometrico tramite...
Zero-day SharePoint: Microsoft punta il ...
Grab & Go, il nuovo Telepass per chi...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 09:07.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Served by www3v