2009-12-17 3 views
5

Ho un server che riceve richieste di connessione dai client. Questo server utilizza il metodo asincrono Socket.BeginReceive e Socket.EndReceive. Il codice è molto simile al codice trovato here.C#: Come posso terminare un socket prima che le chiamate Socket.BeginReceive?

Nel mio caso, dopo aver chiamato Socket.BeginReceive ho bisogno di un timeout tale che se il client si blocca sulla connessione ma non trasmette alcun dato per un periodo di tempo fisso, ho bisogno di terminare la connessione.

  • Come posso terminare la connessione in questo scenario?
  • Qual è il modo migliore di codificare un timer ?

risposta

10

basta chiamare il metodo del socket Close(). Il metodo di callback verrà eseguito piuttosto rapidamente, dopo verrà chiamato il numero ObjectDisposedException quando si chiama il metodo EndReceive(). Siate pronti a cogliere questa eccezione.

Probabilmente non si desidera bloccare il thread chiamato BeginReceive, è necessario un System.Threading.Timer o System.Timers.Timer per rilevare il timeout. Il suo callback dovrebbe chiamare Close(). Prestare attenzione all'immancabile condizione di competizione che causa, la richiamata del timer verrà eseguita se la risposta è stata ricevuta un microsecondo prima della scadenza del timer. Chiudi la presa, anche se hai una buona risposta. La prossima chiamata a BeginReceive() avrà esito negativo immediatamente.

+0

Significa che il metodo di callback verrà eseguito anche dopo aver chiamato il metodo di chiusura del socket? – Lopper

+1

Se è in sospeso BeginReceive(): sì. È sempre * necessario * essere associato a una chiamata EndReceive(). evitare la richiamata –

+0

Grazie nobugz! :) – Lopper

0

Secondo l'articolo di MSDN su Socket.BeginReceive esso afferma

Per annullare una BeginReceive in attesa, chiamare il metodo Close.

+0

E per citare la documentazione per il metodo Close: "Per i protocolli orientati alla connessione, si consiglia di chiamare Shutdown prima di chiamare il metodo Close. Ciò garantisce che tutti i dati siano inviati e ricevuti sulla presa connessa prima che sia chiuso." –

0

È possibile ricevere alcuni dati iniziali in modo asincrono e quindi effettuare Ricezione sincrona per il resto dei dati e fare affidamento su ReceiveTimeout per disconnettere il client. È possibile utilizzare Socket.Close per forzare la disconnessione del client.

Ma se si desidera utilizzare solo Ricezione asincrona, è possibile utilizzare i timer e ripristinarli su EndReceive. Se è trascorso, puoi disconnettere il client con forza.

Ma penso che il primo approccio sia migliore.

7

So che questo thread è piuttosto vecchio ma ho appena riscontrato lo stesso problema e non ero soddisfatto dalla risposta fornita qui (o da qualsiasi altra parte in merito).

Una soluzione migliore per annullare un in sospeso Socket.BeginReceive è chiamare Socket.Shutdown e non Socket.Close. In questo modo il gestore di asynch viene sollevato "normalmente" e una chiamata a Socket.EndReceive restituisce 0 -> invece di generare un'eccezione di previsione brutta. Si dovrebbe sempre avere un

if (Socket.EndReceive() > 0) { 
    //Do something 
} else { 
    //Socket has been shut down (either by you or the other end of the connection) 
    //Now it's "safe" to call Socket.Close 
    Socket.Close(); 
} 

in modo che non hanno nemmeno bisogno di regolare l'asynch-callback per gestire la cancellazione manuale.

Problemi correlati