Newsgroup: it.comp.os.linux.development
Titolo: fallimento di select...

salve,
chiamando la funzione select su di un socket (impostato come 
non-blocking), per verificare se sia possibile effettuare una scrittura 
su di esso (tramite la funzione send), mi capita che il socket non sia 
mai scrivibile!! In particolare, se specifico nessun timeout (quindi 
attesa indefinita), la select non ritorna mai!! Il fatto č che se vado a 
chiamare send su questo socket l'errore specificato č EAGAIN (non 
altri). Qualcuno a qualche idea in proposito?
-- 
[...] to fight and conquer in all your battles is not supreme 
excellence; supreme excellence consists in breaking the enemy's 
resistance without fighting.

 altri). Qualcuno a qualche idea in proposito?
da man 2 connect:
ERRORS
    These are some standard errors generated by  the  socket  layer. ddi-
    tional  errors may be generated and returned from the underlying proto-
    col modules; see their respective manual pages.
  EAGAIN or EWOULDBLOCK
    The socket is marked non-blocking and  the  requested  operation
    would block
quindi mi aspetto che anche connect() abbia restituito errore e settato
errno a EAGAIN, il che e' normale se usi socket non bloccanti, tuttavia
il permanere di questo stato fa credere che l' IP a cui ti vuoi
connettere non sia raggiungibile (manca l' handshake a 3 vie del TCP
syn, syn-ack, ack). l' IP e' raggiungibile?
la posta chiamata e' in listen con un server in ascolto? hai usato
le funzioni di conversione dei valori numerici con ordinamento rete?
htons() ecc..
Comunque se usi select() non ti serve usare socket non bloccanti.
inoltre attento che in select() il set write-ready-set e' in terzo arg.
Ciao
Roberto.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 inoltre attento che in select() il set write-ready-set e' in terzo arg.
Dunque: creo il socket, lo connetto al server remoto e scambio i dati 
con successo. Solo dopo un po' (eventualmente potrebbe anche essere che 
il server remoto sia caduto o simili) la select comincia a dirmi che il 
socket non è più scrivibile. Il fatto è che se provo a ignorare la 
select, send() mi restituisce in ogni caso EAGAIN. Come faccio a capire 
che la connessione è caduta?
grazie dell'aiuto!


 grazie dell'aiuto!
Non sono sicuro di avere capito bene il tuo problema, comunque:
La select non può dirti che "il socket non è più scrivibile", invece ti dice
quando un socket è pronto a ricevere e quindi tu puoi operare la send().
Se imposti la struct timeval in sec e microsec che sei disposto ad attendere
prima di far ritornare la select() hai la possibilità di controllare il
valore di ritorno cho nel caso sia zero ti permette di attestare che la
connessione è caduta e agire di conseguenza.
Ciao,
Fabio De Francesco
 
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/

 connessione è caduta e agire di conseguenza.
Cerco di spiegarmi meglio (mi rendo conto che finora non mi sono 
espresso benissimo):
- ho il socket s non-bloccante, sul quale chiamo send(). send() mi 
restituisce EAGAIN.
stando a quello che dice la documentazione, EAGAIN significa che send() 
non è in grado di completare l'operazione (il socket è non-bloccante), 
devo provare successivamente. A questo punto io posso ritenere che la 
connessione sia caduta? Non lo so, allora meglio fare così:
- ho il socket s non-bloccante, chiamo select() in questo modo:
fd_set write_fds;
FD_ZERO(&write_fds);
FD_SET(s, &write_fds);
struct timeval= {10, 0};	// 10" di timeout
if (select(s + 1, NULL, &write_fds, NULL, &timeouts) < 0)
{
	//...
}
else
{
	if (FD_ISSET(s, &write_fds))
	{
		// posso chiamare send() su s
	}
	else
	{
		// ammettendo che la connessione sia caduta,
		// verifico che se chiamo send() su s la funzione
		// restituisce sempre EAGAIN!! Non dovrebbe essere
		// un altro il codice d'errore? EPIPE per esempio?
	}
}
possibile che se cade la connessione il codice d'errore sia sempre 
'EGAIN'? Come faccio allora a distinguere il caso in cui devo solo 
riprovare la chiamata a send() in seguito?


 riprovare la chiamata a send() in seguito?
Già risposto sopra. Se la select() restituisce timeout (cioè '0') non ha
senso riprovare la chiamata a send(): o provi un'altra select() o chiudi.
EPIPE significa "broken pipe" e non credo sia questo il contesto in cui
l'errore può comparire.
Ciao,
Fabio MDF


Ok, grazie a tutti per la pazienza e la disponibilità.


 riprovare la chiamata a send() in seguito?
Ripeto: per me potrebbe essere che il socket non e' CADUTO, ma NON IS E'
MAI connesso. Dovresti, prima che scada timeout, fare netstat -nta da
altra console e vedete se il socket e' ESTABILISHED o SYS_SENT. Dato che
il socket e' non bloccante, non lo e' anche per connect() che se non puo'
connettersi, ritorna -1 e setta errno a EINPROGRESS. il permanere questo
stato va verificato con select() appunto come si legge in
man 2 connect
per questo ti ho detto che se sei sicuro della raggiungibilita' de server
sulla porta scelta di controllare il corretto uso delle routines di
conversione da interi host a interi rete, magari il tuo intero si e'
trasformato in un IP remoto inaspettato o in una porta remota inaspettata.
P.S. se usi socket bloccante, la connect() ritorna o rimane impiccata??
ciao


 P.S. se usi socket bloccante, la connect() ritorna o rimane impiccata??
nessuna connect, il socket viene creato con la funzione socketpair per 
effettuare consentire il dialogo tra due processi (padre e figlio).


 effettuare consentire il dialogo tra due processi (padre e figlio).
Allora forse il socket non e' veramente pronto per la scrittura, l' altro
processo deve essere in read(), ma se non e' bloccante la read() ritorna
immediatamente... daro' un' occhiata allo Stevens stasera, ma credo che
non puoi usare cosi' socket non bloccanti. Come primo tentativo prova a
settare l' opzione bloccante, anche solo lato processo in read(), cosi'
vedi se il problema e' proprio il controllo di flusso.
In che dominio di protocollo usi socketpair() ??
Ciao
Roberto


 In che dominio di protocollo usi socketpair() ??
guarda, purtroppo non sono per nulla esperto nella programmazione su 
Linux e mi è capitato la manutenzione di questo progetto tra capo e 
collo! Il socketpair crea i due socket nel dominio PF_UNIX e (se non ho 
seguito male il flusso di codice), sono SOCK_DGRAM. La linea di codice è 
questa:
int sockets[]= {-1, -1};
socketpair(PF_UNIX, SOCK_DGRAM, 0, sockets);
Ora sto cercando di creare un paio di test per cercare di capire meglio 
come funzionano queste cose altrimenti non ne vengo più fuori, in più vi 
faccio perdere del tempo per niente.


 faccio perdere del tempo per niente.
cavolo, potevo farlo prima...
creando una socket con la seguente linea:
int fds[2];
socketpair(PF_UNIX, SOCK_DGRAM, 0, fds);
è possibile effettuare con successo diverse send su uno dei due socket 
anche senza la chiamata di recv sull'altro, dopodichè tutte le ulteriori 
send restituiranno EAGAIN, finchè (suppongo) non si svuoti il buffer di 
ricezione dell'altro socket.
