Keepalive di un socket

giovedì 04 agosto 2005 - 13.10

ffederico Profilo | Newbie

ho il seguente problema.
ho la necessita' di essere avvisato quando il socket di un client si disconnette.

ho due applicazioni.
ilclient che inizializza il socket (s1), imposta l'opzione di keepalive e poi si connette.
il server che riceve un nuovo socket dalla Accept() e comincia a comunicare con il client con questo nuovo socket (s2).

il problema che ho e' che il nuovo socket del server (s2) non si accorge che la connesione con il client (s1) viene interrotta.

il problema credo sia dovuto al fatto che, la Accept() ritorna un socket gia' connesso a cui non e' piu' possibile impostare la proprieta' di keepalive.

ho provato ad impostare tale proprieta' anche sul socket server ma senza risultati.

qualche soluzione?
grazie.

LudovicoVan Profilo | Junior Member

E' tanto che non mi capita di lavorare direttamente con i socket, ma da quel che ricordo per verificare se il client è ancora connesso occorre inviargli qualche byte di prova a intervalli e rilevare l'errore di invio. Naturalmente il client deve essere a sua volta implementato in modo da ignorare/scartare i byte in eccesso.

Ciao. -LV


(Peace X Love] = [1)

ffederico Profilo | Newbie

risolto.
ma una cosa alla volta.

inviare byte in ping non e' una cosa carina. almeno a me non piace. il keepalive e' una caratteristica del socket a basso livello e mi sembra giusto che sia lui a farla piuttosto che io.

ho comunque trovato al soluzione al problema. devo dire pero' che in questo la guida mi ha tratto in inganno.

testualmente recita "Accept synchronously extracts the first pending connection request from the connection request queue of the listening socket, and then creates and returns a new Socket." probabilmente e' colpa del mio inglese ma quel "new Socket" mi ha ingannato. infatti io continuavo a provare il seguente codice

s = m_sck.Accept(); // bloccato
s.SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, 5000);

ma non funzionava. funziona invece in questo modo:

s = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
s.SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, 5000);
s = m_sck.Accept(); // bloccato

et voila'.


federico

ffederico Profilo | Newbie

Dimenticavo,

nei sistemi a 32 bit, anche se procedi come dici, non sai, fino allo scadere del timeout, se effettivamente il socket dall'altro lato e' caduto.

il meccanismo che indichi non funziona. deve essere invece nella forma di un ack/nak, cioe' verificare i tempi della risposta e non l'esito dell'invio.

questa cosa, ripeto sui con il framework .NET, mi ha fatto perdere tanto tempo in passato. il sistema, con i socket, fino al timeout non ti notifica mai se dall'altro lato il client si e' disconnesso.

prova a staccare il cavo di rete e vedrai che i due client connessi non se ne accorgono anche se effettui delle send.
te ne puoi accorgere solo se dopo aver effettuato la send, ti aspetti una risposta che non ti arriva (appunto ack/nak).

federico

LudovicoVan Profilo | Junior Member

Buono che hai risolto con il keep-alive.

>nei sistemi a 32 bit, anche se procedi come dici, non sai, fino
>allo scadere del timeout, se effettivamente il socket dall'altro
>lato e' caduto.

Questo non mi risulta. Qui non si tratta di leggere ma di scrivere e il send va in errore immediatamente... almeno mi ricordo che questo era l'approccio quando facevo network programming sotto Unix, ma il sistema operativo non dovrebbe fare differenza.

Ciao. -LV

(Peace X Love] = [1)

LudovicoVan Profilo | Junior Member

BTW, per completezza, il keep-alive fa esattamente la stessa cosa dietro le quinte, ovvero invia dei byte al client per rilevare l'eventuale errore al send. -LV

(Peace X Love] = [1)

ffederico Profilo | Newbie

so perfettamente che il keepalive fa la stessa cosa. solo che visto che lo fa lui non vedo perche' devo metter su un sistema io che faccia lo stesso.

per quanto riguarda invece il discorso dei socket, purtroppo non e' come dici tu e come era fino alle versioni NON in ambiente .NET.

leggi qui:
"If you are using a connection-oriented protocol, Send will block until all of the bytes in the buffer are sent. In nonblocking mode, Send may complete successfully even if it sends less than the number of bytes in the buffer. It is your application's responsibility to keep track of the number of bytes sent and to retry the operation until the application sends the bytes in the buffer. There is also no guarantee that the data you send will appear on the network immediately. "

come puoi leggere dall'ultimo paragrafo, non ti viene notificato subito se la trasmissione e' andata a buon fine o meno.

se vuoi, puoi provare, come ho gia' fatto io, a fare una prova del genere.

crei du eapplicazioni socket, le lanci su due macchine diverse e le metti in comunicazione.

stacca i lcavo di rete ad una delle due macchine e spedisci qualcosa.

vedrai che la spedizione avverra' senza errori.

federico

LudovicoVan Profilo | Junior Member

>so perfettamente che il keepalive fa la stessa cosa. solo che
>visto che lo fa lui non vedo perche' devo metter su un sistema
>io che faccia lo stesso.

Nessuno ti ha detto il contrario.

>come puoi leggere dall'ultimo paragrafo, non ti viene notificato
>subito se la trasmissione e' andata a buon fine o meno.

Basta usare flush()...

Complimenti per la simpatia. -LV

(Peace X Love] = [1)

ffederico Profilo | Newbie

intanto scusami per 'la simpatia'.
non mi ero accorto di essere stato cosi' antipatico.

per quanto riguarda il metodo flush(), purtroppo per i socket non sono riuscito a trovarlo.
forse ho cercato male.

ciao e grazie per la pazienza.

federico
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5