Newsgroup: it.comp.os.linux.development
Titolo: socket: capire quando il client non c'è più

Sto scrivendo una classe in c++ che deve fare da server che gestisce un
signolo thread alla volta. Sembra funzionare, ma ho un problema: se il
client si disconnette il server continua a credere si essere connesso . 
Io mi aspetterei un mel ritorno di -1 dalla read o dalla recv e invece sta
lì come un fesso.
il codice è
while (i = recv (slaveSocket, (void *)frame, 10 * sizeof (char), MSG_WAITALL) != -1)
{
 if (i < 0)
  break;
 if (i != 10)
  while (i != 10 && i >= 0)
   i += recv (slaveSocket, (void *) (frame + i), (10 - i) * sizeof (char), MSG_WAITALL);
Come faccio a sapere quando il client se ne è andato? Non mi esce mai
dall'attesa del primo while...

lě come un fesso.
solo un'idea.. stai provando in locale ? 
Recentemente scrivendo un programmino con i socket ho avuto lo stesso
problema, in local -1 nella read non esce mai.. esce perň alla prima
write. linux 2.4. boh

 write. linux 2.4. boh
e se i client sono remoti funziona? No, perché saprebbe da baco....



ecco, ho fatto la prova, non ritorna nemmeno se i processi sono su pc
diversi.

 while (i = recv (slaveSocket, (void *)frame, 10 * sizeof (char), MSG_WAITALL) != -1)
Ti serve comunque una coppia di parentesi attorno all'assignment.
Ciao
  David
-- 
<d.santinoli presso mi. flashnet. it>


Provato anche con select()?
Alessandro.

 Ti serve comunque una coppia di parentesi attorno all'assignment.
provato non cambia niente

 Provato anche con select()?
e anche con poll. non cambia niente.

 lì come un fesso.
Perché ti aspetti che restituisca -1? Se il client si è disconnesso, 
read/recv restituisce 0.
Max

 while (i = recv (slaveSocket, (void *)frame, 10 * sizeof (char), MSG_WAITALL) != -1)
[...cut] 


 -1. Prova un po' così. NemU
si per te che per max, nè read nè recv ritornano ma stanno lì come dei
cretini... se ritornasse sarebbe ottimo, perché la seconda volta che la
chiami dovrebbe avivsarti che il socket decriptor non è valido...

 chiami dovrebbe avivsarti che il socket decriptor non č valido...
Finche non lo chiudi il descrittore resta valido. Se continui a chiamare 
'recv', questa continua a restituire 0.
Max

 'recv', questa continua a restituire 0.
non c'č modo di farsi mandare un bel SIGPIPE che mi avverte che
all'altro estremo non c'č piů nessuno? Come avviene per le pipe. Sarebbe
carino

 carino
Il SIGPIPE c'č anche per i socket, ma si produce soltanto nelle operazioni 
di scrittura (v. man 2 write). 
Max

e se i client sono remoti funziona? No, perché saprebbe da baco....
E s che andava :)
mah, che dire.. il mio prof di SO mi ha stordito con una spiegazione
sulla macchina a stati dello stack tcp/ip e sul'implemnentazione dei
socket unix, non ho capito una mazza, tanto alla fine funzionava..

 di scrittura (v. man 2 write). 
che peccato. E se ritorna zero e richiamo la recv non c'è modo che
ritorni qualche errore, come EBADF ?

             (10 - i) * sizeof (char), MSG_WAITALL);
Scusa, ma questo codice, così com'è, non ti permette di diagnosticare il 
comportamento che hai descritto: non c'è alcuna verifica che il valore 
restituito da 'recv' sia diverso da 0 e non è possibile distinguere 
il caso in cui il programma è fermo in una 'recv' da quello in cui resta 
permanentemente nel secondo ciclo 'while'.
Io, comunque, lo riscriverei aggiungendo una funzione:
  int recv_n( int fd, char* ptr, size_t len, int flags )
  {     size_t read = 0;
        while( read < len )
        {  int rc = recv(fd, ptr+read, len-read, flags);
           if( rc <= 0 ) return rc;
           read += rc;
         }
        return read;
  }
Quindi:
   while(1)
   {
        int i = recv_n (slaveSocket, frame, 10, MSG_WAITALL);
        if( i <= 0 ) break;
        /* etc... */
   }
Max

    }
proverò.

 no, l'ho visto col gdb
Guarda, ho provato il tuo codice su diverse piattaforme (Linux 2.2.14, 
Linux 2.4.18, Solaris), con client sulla stesso host o su host diverso, e 
in nessun caso sono riuscito a riprodurre il comportamento che hai 
descritto.
Questo è quello che dicono le Unix Socket FAQ a questo proposito:
 
http://www.ibrado.com/sock-faq/#faq8
 If the peer calls close() or exits, without having messed with SO_LINGER, 
 then our calls to read() should return 0. It is less clear what happens to 
 write() calls in this case; I would expect EPIPE, not on the next call, 
 but the one after.
 If the peer reboots, or sets l_onoff = 1, l_linger = 0 and then closes, 
 then we should get ECONNRESET (eventually) from read(), or EPIPE from 
 write().
Domani darò uno sguardo allo Stevens che ho in ufficio.
Max

  write().
aspetta aspetta, cosa vuol dire questo? devo chiamare setsockopt sul
descrittore del client? 

 Io, comunque, lo riscriverei aggiungendo una funzione:
l'ho provato, cosě funziona. grazie
adesso torno al vecchio sorgente a capire che cavolo non funzionava.

 lì come un fesso.
Se ricordo bene questo problema e' noto come half-open connection: il 
server aspetta indefinitamente di ricevere qualcosa dal client che 
invece e' terminato in modo non 'consono'. Se il client chiude il socket 
il server se ne accorge (mi pare che venga usato un msg OOB).
Le soluzioni possono essere 2: o usi l'opzione KEEPALIVE standard dei 
socket (circa 2 ore di timeout) o metti una select con timeout come ti 
pare prima della recv.
Ciao,
Stefano.