PDA

View Full Version : C programmazione socket, problemino, spero semplice.


Abdujaparov
25-03-2006, 18:13
Salve a tutti, ho un piccolo problemino. Sto scrivendo un semplice client ed un semplice server che scambiano i dati in binario, dopo averli convertiti in formato di rete.
Ora i dati devo essere inviati in questo ordine. Un primo byte con un numero, un altro byte con la dimensione del numero nei restanti byte, cioè invio un byte con il numero 8, poi invio il secondo byte con la dimensione del numero che invio come terzo argomento, per esempio 2 se invio un uint16_t, 4 se invio un uint32_t e poi invio il numero uint16_t o uint32_t.
Ora ho i seguenti problemini:
1) i primi due byte contengono un uint8_t ciascuno, come posso applicare la conversione in formato di rete (ntohs) se questa funzione mi restituisce un uint16_t?
2)Io per inviare questi dati al server li scrivo ad uno ad uno sul socket, per leggerli sul server io ho messo una read senza altri accorgimenti ma così facendo mi viene letto solo il primo numero, come faccio a far leggere gli altri due?
3)Se volessi mettere i dati da inviare in un buffer e poi inviare il buffer come dovrei fare? Io creo un array di char, nelle prime due posizioni inserisco i primi due byte, nelle restanti posizioni come posso copiare il terzo numero che sta su più byte?

Grazie a tutti, ciao ciao.

mr_hyde
25-03-2006, 20:35
Non credo di aver capito bene...

Ricorda che vanno convertiti solo i tipi di dati che vengono memorizzati su piu' byte (quindi gli interi che sono su 2 o 4 byte).
Per i byte "singoli" invece non ci sono problemi, non c'e' la necessita' di convertirli.

Se ho capito bene, il tuo "pacchetto dati" e' una cosa del tipo:

typedef BYTE unsigned char;

BYTE the_id; /* vale sempre 8*/
BYTE the_size; /* contiene un valore numerico corrispondente al numero di byte che seguono */
BYTE* the_buffer; /* e' l'array di byte spedito/ricevuto, grande quanto indicato da the_size */

Se ho capito bene, puoi fare la segg. cosa per ricevere:

typedef struct headerTemplate {
BYTE the_id; /* vale sempre 8*/
BYTE the_size; /* contiene un valore numerico corrispondente al numero di byte che seguono */
} __attrbute__(packed)) headerType;


/* prima di tutto ricevo il pacchetto */
int rslt;
headerType the_header;
BYTE* pBuffer = NULL;

rslt = recv(socketId, (void*) &the_header, sizeof(headerType));
if (rslt < 0)
{
/* qualcosa e' andato storto */
perror("recv - some problem");
close(socketId);
return;
}

/* controllo l'id del pacchetto */
if (the_header.the_id != VALORE_CHE_MI_ASPETTO)
{
fprintf(stderr, "Got unexpected header. Id = 0x%2x\n", the_header.the_id);
close(socketId);
return;
}

/* a questo punto posso creare un buffer per ricevere il dato vero e proprio */
/* preparo il buffer di ricezione */
pBuffer = malloc(the_header.the_size);
if (pBuffer == NULL)
{
perror("malloc");
close(socketId);
return;
}

/* ed ora ricevo realmente il buffer */
rslt = recv(socketId, (void*) pBuffer, the_header.the_size);
if (rslt < 0)
{
/* qualcosa e' andato storto */
perror("recv - some problem while receiving data");
close(socketId);
return;
}


/* elabora pBuffer */


free(pBuffer);
close(socketId);

NOTA: l'ho buttata giu' cosi', sicuramente ci sono errori, quindi non prendere queste 2 istruzioni come oro colato!

NOTA2: eventualmente e' nel punto "elabora pBuffer" che devi usare le funzioni di conversione sul buffer ricevuto

NOTA3: ho scritto la struttura dell'header SOLO PER "DIDATTICA" (in questo semplice esempio non mi sembra che in realta' serva) infatti senza l'attributo packed, NON e' detto che la sizeof di una struttura corrisponda alla somma delle sieof dei singoli componenti della struttura.

Spero che come traccia ti possa andar bene.

Ciao,
Mr Hyde

Abdujaparov
26-03-2006, 22:11
Grazie per l'aiuto, in pratica io devo creare un server per un client di cui conosco solo il protocollo di comunicazione e quindi sto cercando di replicare un client di prova per testare il server. Per inviare i dati uso una struttura solo che c'è qualche problemino sulla dimensione dei dati inviati.
Io invio la struttura al server che effettivamente riceve 4 byte, poi cerco di far rispondere il server e invio una struttura con un byte che indica lo stato e due bytes che indicano il risultato di un'operazione, solo che quando invio i dati la struttura mi viene detto che è composta da 4 byte e non da 3 byte come dovrebbe essere. Un'altra cosa, il mio client dopo aver inviato i dati dovrebbe rimanere in attesa di una risposta dal server solo che mi viene lanciato un errore di segmentation fault.
Un'altra cosa se io volessi inviare i dati al server scrivendo 3 write es:

write(socket, primoByte, sizeof(primoByte));
write(socket, secondoByte, sizeof(secondoByte));
write(socket, ultimi2Byte, sizeof(ultimi2oByte));

Nel server cosa dovrei mettere per leggere tutti e 4 i byte?
Una semplice n=Read(socket,rbuf,MAXBUFF) non funziona, mi legge solo il primo byte. Come dovrei modificare il server per far ricevere sia i byte inviati in questo modo che quelli inviati con una struttura? Il client che sto scrivendo io è solo un "emulatore" per un client che non ho ma di cui ho solo le specifice sul protocollo di comunicazione.

Ti allego le parti che mi danno problemi.
Server:
uint16_t ris = sqrtn(base2, radice); //effettuo l'operazione radice n-esima
ris=htons(ris); // converto il risultato in formato di rete
struct risposta{uint8_t uris; uint16_t risultato;} dati; //definisco la struttura (dovrebbe essere 3 byte)
dati.uris=0; //imposto lo stato
dati.risultato=ris; //assegno risultato
#ifdef TRACE
err_msg("La dimensione dello stato è: %u\n", sizeof(dati.uris)); //mi viene dato 1
err_msg("La dimensione del risultato è: %u\n", sizeof(dati.risultato)); //mi viene dato 2
err_msg("La dimensione della risposta è: %u\n", sizeof(dati)); //mi viene dato 4?? Io devo rispondere per forza con 3 byte
#endif
Writen(connfd, &dati, sizeof(dati)); //invio i dati

Client:
invio.radice=3; //imposto i dati della struttura che invio
invio.dim=sizeof(pippo);
invio.operando=pippo;

#ifdef TRACE
err_msg("Dati inviati: %u\n", sizeof(invio));//la dimensione della struttura qua è correttamente 4
#endif

Writen(socket,&invio,sizeof(invio)); //invio la struttura
//qua mi viene dato segmentation fault, cosa posso avere sbagliato?
n=Read(socket,rbuf,MAXBUFF);

Grazie, ciao ciao.

mr_hyde
26-03-2006, 22:24
Mi auto-quoto per quanto riguarda la tua struttura che DOVREBBE essere di 3 byte ma in realta' e' di quattro:


NOTA3: ho scritto la struttura dell'header SOLO PER "DIDATTICA" (in questo semplice esempio non mi sembra che in realta' serva) infatti senza l'attributo packed, NON e' detto che la sizeof di una struttura corrisponda alla somma delle sieof dei singoli componenti della struttura.


__attribute__((packed)) e' la "clausola" che si usa con il compilatore gcc e su altri compilatori sotto Unix, se tu ne usi altri probabilmente devi mettere una cosa tipo "PACKED": questo fa in modo che gli elementi di una struttura vengano memorizzati esattamente uno consecutivamente all'altro e che non vengano aggiunti altri pezzi in coda (altrimenti il compilatore, per motivi vari, puo' decidere di fare diversamente).

Per il resto: ora e' un po' tardi, leggero' un po' meglio il messaggio e poi ti rispondero'

Ciao,
Mr Hyde

Abdujaparov
27-03-2006, 06:31
Ti ringrazio per l'informazione sulla struct solo che il server deve essere compilato sotto varie piattaforme e non solo uni e questo potrebbe essere un problema, per questo sarebbe interessante capire come inserire i dati in un array di char o come ricevere i dati dopo 3 write consecutive.
Grazie, ciao ciao.

mr_hyde
27-03-2006, 22:51
Grazie per l'aiuto, in pratica io devo creare un server per un client di cui conosco solo il protocollo di comunicazione e quindi sto cercando di replicare un client di prova per testare il server. Per inviare i dati uso una struttura solo che c'è qualche problemino sulla dimensione dei dati inviati.
Io invio la struttura al server che effettivamente riceve 4 byte, poi cerco di far rispondere il server e invio una struttura con un byte che indica lo stato e due bytes che indicano il risultato di un'operazione, solo che quando invio i dati la struttura mi viene detto che è composta da 4 byte e non da 3 byte come dovrebbe essere. Un'altra cosa, il mio client dopo aver inviato i dati dovrebbe rimanere in attesa di una risposta dal server solo che mi viene lanciato un errore di segmentation fault.
Un'altra cosa se io volessi inviare i dati al server scrivendo 3 write es:

write(socket, primoByte, sizeof(primoByte));
write(socket, secondoByte, sizeof(secondoByte));
write(socket, ultimi2Byte, sizeof(ultimi2oByte));

Nel server cosa dovrei mettere per leggere tutti e 4 i byte?
Una semplice n=Read(socket,rbuf,MAXBUFF) non funziona, mi legge solo il primo byte. Come dovrei modificare il server per far ricevere sia i byte inviati in questo modo che quelli inviati con una struttura?


Io generalmente uso recv, ma il comportamento dovrebbe essere lo stesso di read.
Quindi se fai:

char buffer[4];
int n;
n = read(socket, (void*) buffer, 4)

ti viene in realta':
1) restituito 1
2) letto quindi solo il primo byte?

In teoria dovrebbe funzionare, la read restituisce un numero minore rispetto alla lunghezza solo in alcune condizioni (signal, errori...).
Un dubbio: non e' che dal lato server chiudi la connessione non appena spediti i 3 byte?



Il client che sto scrivendo io è solo un "emulatore" per un client che non ho ma di cui ho solo le specifice sul protocollo di comunicazione.

Ti allego le parti che mi danno problemi.
Server:

uint16_t ris = sqrtn(base2, radice); //effettuo l'operazione radice n-esima
ris=htons(ris); // converto il risultato in formato di rete
struct risposta{uint8_t uris; uint16_t risultato;} dati; //definisco la struttura (dovrebbe essere 3 byte)


dall'altro 3ad ho visto che l'hai resa packed, spero quindi che questo abbia risolto il problema della lunghezza strana



dati.uris=0; //imposto lo stato
dati.risultato=ris; //assegno risultato
#ifdef TRACE
err_msg("La dimensione dello stato è: %u\n", sizeof(dati.uris)); //mi viene dato 1
err_msg("La dimensione del risultato è: %u\n", sizeof(dati.risultato)); //mi viene dato 2
err_msg("La dimensione della risposta è: %u\n", sizeof(dati)); //mi viene dato 4?? Io devo rispondere per forza con 3 byte
#endif
Writen(connfd, &dati, sizeof(dati)); //invio i dati



scusa ma cosa fa la "writen"? Io su Linux non la ho


Client:

invio.radice=3; //imposto i dati della struttura che invio
invio.dim=sizeof(pippo);
invio.operando=pippo;

#ifdef TRACE
err_msg("Dati inviati: %u\n", sizeof(invio));//la dimensione della struttura qua è correttamente 4
#endif



Attento quando usi la sizeof con il nome di una variabile invece che con il tipo: puoi sbagliare specialmente nel passaggio di parametri, quando passi ad una funzione un array.

Per maggiori dettagli sull'uso di sizeof vedi

http://publications.gbdirect.co.uk/c_book/chapter5/sizeof_and_malloc.html

(sul fondo della pagina e' riportato un errore comune)



Writen(socket,&invio,sizeof(invio)); //invio la struttura
//qua mi viene dato segmentation fault, cosa posso avere sbagliato?
n=Read(socket,rbuf,MAXBUFF);



Ti riferisci alla read?
Non vedo la dichiarazione di rbuf e neppure la definizione di MAXBUFF, Sicuro sia tutto ok?

Ciao,
Mr Hyde