Newsgroup: it.comp.programmare
Titolo: big/little endian su trasmissione tcp

Ciao a tutti, sto cominciando a programmare su unix tcp.
ho letto una guida in cui c'e' scritto che bisogna prevedere il fatto che
se trasmetto ad esempio un integer a 2 byte, devo prevedere il fatto che
se trasmetto da una macchina big endian a una little endian devo invertire
l'ordine.
ma la trasmissione "standard" deve essere big endian o little endian?
-- 
Spolvera la mia email per rispondermi
"Storia del Mondo. I vulcani eruttarono. Gli oceani ribollirono.
L'universo era in tumulto. Poi venne il cane."
Snoopy
maxy04.splinder.com
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

ma la trasmissione "standard" deve essere big endian o little endian?
Che intendi per "standard"?

Andrea Laforgia ha scritto:



cioe' nel senso:
creo un programma in c++ che poi verra' compilato su sun e pc, ed eseguito
su un pc e una sun, che dialogano tra loro.
a rigor di logica, deve essere il sun a invertire i bit quando trasmette o
il pc?


 il pc?
Ma che senso ha tutto cio?
Il TCP/IP e' un sistema di trasporto: quello che mandi arriva.
La natura del dato che trasporti dipende dal protocollo che implementi 
sopra il TCP/IP.
E in ogni caso i protocolli sono gia' definiti, a meno che non intendi 
creartene uno custom, e allora ti inventi un po' quello che ti pare.
Oppure non ho capito niente di quello che stai chiedendo.

il pc?
Non c'è un "rigor di logica", si tratta di convenzioni. Tieni presente
che a livello più basso, di solito i dati vengono trasferiti con un
network order (big-endian), ma ciò non implica necessariamente che i
dati dell'applicazione debbano avere la stessa endianess. Sei libero
di trasmettere i dati come vuoi, purché le due applicazioni si
accordino su come interpretarle.

sopra il TCP/IP.
Il TCP/IP non c'entra. La natura del dato che viene trasportato
dipende dalla convenzione tra le applicazioni.

 ma la trasmissione "standard" deve essere big endian o little endian?
Non ti devi preoccupare di quale sia l'endiannes giusta.
Devi solo convertire l'endianness da quella dell'host a quella della
rete e viceversa. Quale siano esattamente queste endianness non ti
riguarda.
Usa queste funzioni (prese dal man di linux, ma presenti (credo) sulla
maggior parte delle architetture):
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
htonl significa (host)to(network)(long), ovvero converte l'endianness
di un long da quella dell'host a quella della rete.
Cosa fanno le altre funzioni viene da se'...
Saluti,
The Librarian

 uint16_t ntohs(uint16_t netshort);
...
     The byteorder functions are expected to conform with IEEE Std
     POSIX.1-200x (``POSIX.1'').
Insomma, ci si puņ aspettare di trovarle su tutti i sistemi posix.
-- 
cc = callcc {|cc| cc.call cc}; cc.call cc

Insomma, ci si può aspettare di trovarle su tutti i sistemi posix.
...quindi anche Windows.

 ...quindi anche Windows.
Non tutte le versioni, AFAIK. O meglio, alcune hanno semplicemente
bisogno di un pacchetto aggiuntivo.
Per inciso, usando una cosa tipo cygwin (e forse pure mingw) direi che
c'è comunque. 


 Cosa fanno le altre funzioni viene da se'...
grazie mille.
quindi posso usare, per gli stessi motivi, le stesse funzioni
eventualmente per la scrittura/lettura di file.


uint16_t ntohs(uint16_t netshort);
Supponendo di  trasmettere i dati sempre come "network ordered" ,
se ci sono pero' anche dati a 64bit, va poi aggiunta una funzione ad oc 
relativa
per la conversione da network order a host e viceversa, visto che manca
una funzione 'standard'.
Ovviamente la struttura del pacchetto deve comunque essere nota a priori
per potere applicare le trasformazioni del caso ai campi specifici :-)
Tra l' altro, con questo approccio macchine che lavorano in big endian  non
necessitano in effetti di fare nessuna conversione .....
----------------------
Pero' , per evitare conversioni inutili, specie se si ha una discreta mole 
di dati,
o strutture un poco complicate,  si potrebbe ricorrere a qualche artificio:
 il maggior produttore dei  dati li trasmette  secondo il proprio ordine
(big o little endian che sia), se poi il ricevente puo' essere una stazione 
con ordine
diverso, si ricorre ad un trucco, tipo quello di  premettere davanti ad essi 
un marker
a 32 bit contenente un valore tipo 0x12345678:
se il marker viene ricevuto con lo stesso valore, non e' necessario fare
conversione, altrimenti occorre applicare una conversione da big a little (o 
viceversa).
Che so,
typedef struct net_pack{
    uint32_t    endianCk;    /* deve essere 0x12345678 */
    /* Dati da inviare */
    uint32_t    dato32[10];
    uint16_t    dato16[18];
    uint8_t      dato8[4096];        /* Non necessita di conversione ! */
    uint64_t    dato64[38];
    uint8_t      altroDato8_0;
    uint8_t      altroDato8_1;
    uint8_t      altroDato8_2;
    uint8_t      altroDato8_3;
}MY_DATA_T;
if (0x12345678 != pData->endianCk)
{
    /* Devo convertire i dati , l' endianess e' diversa! */
    ..........................
}
/* I dati sono ordinati correttamente */
Tra l' altro, bisogna anche verificare che le struture dati siano
correttamente allineate, per evitare problemi dovuti a byte
di padding, che possono essere diversi da una macchina
all' altra, ma questo e' un altro problema :-)
brix

 all' altra, ma questo e' un altro problema :-)
L'allineamento e' una bella rottura di scatole ;-)
Io di solito vado di __attribute__ ((__packed__)) su gcc o #pragma
pack(1)  su VC++ ma quanto a portabilita' fa schifo. Non e' che
conosci un modo migliore?
Saluti,
The Librarian

   
No, salvo lavorare in assembly :-(
E rigrazia che usi il c/c++, una roba del genere in VB e simili e' un 
incubo.
brix