PDA

Visualizza la versione completa : [C] read() socket af_unix return 0


Smoke666
17-12-2012, 12:31
Ciao a tutti, ho un problema con la lettura da un socket. Ho 3 processi server che devono comunicare con un numero variabile di processi client, tuttavia alcuni messaggi non vengono scambiati come dovrebbero e la chiamata a read() che effettua il server per leggere dal socket il messaggio depositato dal client mi restituisce 0. So che questo valore significa che il socket è stato chiuso da una delle due parti, ma non capisco chi lo chiude! Il cliente non lo chiude esplicitamente (ho rimosso questa porzione di codice per verificare che non vi fossero anomalie, ma il problema permane). Il codice è abbastanza semplice: il server accetta una connessione e avvia un thread, che prende come parametro il valore ritornato dalla accept. Il thread è incaricato di leggere il messaggio da questo socket descriptor.

server:


pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
while(1){
if( (acp = accept(fd_sock, NULL, NULL)) != -1 ){
thread = pthread_create(&t_id[i], &attr, worker, (void*)&acp);
if(thread == -1)
perror("Crezione thread");
i++;
}
}


il thread riceve il messaggio, chiamando 3 volte la receive, leggendo rispettivamente: un char, un int e una stringa.



int sock = *(int*)acp;
memset(msg, 0, sizeof(message_t));

while( (letti+= read(sock, &msg->type, sizeof(char) < sizeof(char)) )
if( letti <= 0){
return -1;
perror(Leggo char);
}

while( (letti_int+= read(sock, &msg->length, sizeof(unsigned int) < sizeof(unsigned int)) )
if( letti < sizeof(unsigned int) ) {
perror(Leggo int);
return -1;
}

while( (letti_buf+= read(sock, msg->buffer, msg->length)) < msg->lenght)
if( letti_buf <= msg->length){
perror(Letto buffer);
return -1;
}


Il cliente invece si limita a fare la write sul socket. Questa è corretta perchè invia il numero effettivo di byte.

A volte la prima read, quella che legge il char ritorna 0. Tuttavia il socket non è stato chiuso da nessuno! Come dovrei procedere per correggere l'errore?

Per chiarezza, la struttura msg contiene un char, un unsigned int e un char*.

c0der
17-12-2012, 13:10
Sai com'è, l'errore potrebbe essere ovunque, un puntatore o un sizeof sbagliato, come è già successo (quando fai copia/incolla inoltre dovresti fare più attenzione perché mancano diverse parentesi).

Dovresti fare un un programma server e client minimali (vedi http://sscce.org/) che inviano anche sempre la stessa struttura e provare con un solo server e un solo client. Se già così hai il problema sarà già più facile da debuggare.
Inoltre una volta creato puoi postarlo qui direttamente (sia il client che il server, non solo il server) e sarà più facile da studiare.

Puoi anche postare qui la versione attuale, certo che se è una cosa gigantesca e che nessuno può compilare/provare non è tanto comodo. In questi casi dove trovare il problema può essere complesso è sempre meglio fare una versione ridotta ma che compila e lavorare su quella.

Smoke666
17-12-2012, 13:43
Al momento ho testato la versione completa del programma con 12 client e 3 server, e funziona se i clienti vengono avviati in maniera sequenziale. Ora invece devo testare la versione competitiva, dunque i clienti sono avviati tutti insieme. Riduco il più possibile il codice e cerco di postarlo.

c0der
17-12-2012, 13:53
Ok, mi sfugge solo la differenza tra sequenziale e competitiva. Se li esegui dallo stesso computer sarà sempre sequenziale. (ma comunque anche se esegui i client da computer diversi, le richieste verranno accettate dalla accept() del server una per volta).

Forse con sequenziale intendi che metti una sleep tra l'avvio di un client e l'altro, mentre competitiva senza nessuna sleep?

Smoke666
17-12-2012, 14:22
Con sequenziale intendo che l'avvio di un client avviene dopo la terminazione del precedente. Facendolo con uno script basta semplicemente:

./client parametri
./client parametri1
./client parametri2

In questo modo se prima non termina l'esecuzione di un comando, il secondo non si avvia.

Con competitivo intendo che i client sono in esecuzione in contemporanea. Anche qui con uno script:

./client parametri &
./client parametri1 &
./client parametri2 &

L'attesa della terminazione di un comando non c'è con l'aggiunta dell'esecuzione in background.

c0der
17-12-2012, 14:33
Ora è chiaro, nel post precedente avevi scritto "se i clienti vengono avviati in maniera sequenziale". Tu volevi dire non "avviati" ma "eseguiti e terminati".

Certamente il server ti deve funzionare anche con più client eseguiti in contemporanea, su questo non ci piove.

Smoke666
18-12-2012, 13:22
Ho semplificato il codice, eliminando le librerie. Ora ci sono tutte le funzioni minime per il funzionamento del client e del server. Ho inserito anche uno script per l'avvio, ma anche qui ci sono problemi...Ho messo tutto in un archivio per non creare confusione, è accessibile qui:

my_client_server (https://www.dropbox.com/s/9pgqagpt536sge3/cliser.tar)

c0der
18-12-2012, 14:07
Sul client sono sbagliate le solite due righe:

< letti += read(sc, risposta.type, sizeof(char));
> letti += read(sc, &risposta.type, sizeof(char));

< letti += read(sc, risposta.length, sizeof(unsigned int));
> letti += read(sc, &risposta.length, sizeof(unsigned int));

corretto questo e qualche warning (non lasciare nessun warning di compilazione altrimenti poi non vedi i warning importanti) se eseguo test.sh mi scrive:

$ ./test.sh
Server riceve: 15, x,
Client riceve: 15, x,
Server riceve: 15, x,
Client riceve: 15, x,

È corretto? Se è corretto devo fare invece qualche altro test?

P.S. Non l'ho guardato molto il codice, ci sono varie cose che non hanno senso secondo me ma per adesso le ignoro non essendo la causa del tuo problema di chiusura del socket che lamenti.

Smoke666
18-12-2012, 14:15
Manca il il messaggio contenuto in "messaggio->buffer" (dovrebbe stampare 15, x, provaprovaprova) inoltre questo codice se eseguito con più clienti restituisce l'errore che cito nel titolo. Ho parzialmente risolto utilizzando i thread detached, ma il problema rimane.

c0der
18-12-2012, 14:19
Scusa, mi posso anche andare a guardare il codice, ma hai postato questi due file ser.c e cli.c

Sul tuo computer se li compili così come sono ed esegui in una shell:
./ser
e in un altra shell nella stessa directory:
./cli
cosa ti stampa?

A te stampa "provaprovaprova"? Perché se neanche questo funziona non capisco perché non te lo sei corretto tu. Qui non dovevamo guardare solo perché il socket si chiudeva?

Loading