Come è possibile verificare se un socket di rete (System.Net.Sockets.Socket) è ancora connesso se l'altro host non ti invia un pacchetto quando si disconnette (ad esempio perché disconnesso in modo non corretto)?Come verificare se un socket è collegato/disconnesso in C#?
risposta
Come Paul Turner risposta Socket.Connected
non può essere utilizzato in questa situazione. È necessario eseguire il polling della connessione ogni volta per verificare se la connessione è ancora attiva. Questo è il codice che ho usato:
bool SocketConnected(Socket s)
{
bool part1 = s.Poll(1000, SelectMode.SelectRead);
bool part2 = (s.Available == 0);
if (part1 && part2)
return false;
else
return true;
}
Funziona così:
s.Poll
restituisce vero se- connessione è chiusa, azzerato, terminati o in corso (che significa nessuna connessione attiva)
- connessione attiva e sono disponibili dati per la lettura
s.Available
restituisce il numero di byte disponibili per la lettura- se entrambe sono vere:
- non vi sono dati disponibili per la lettura in modo connessione non è attiva
Proprietà Socket.Connected
.
Basta notare che, anche se Socket.connected restituisce true, la presa potrebbe non essere collegata. Se è falso, non è sicuramente connesso. – nos
La proprietà Socket.Connected
ti dirà se una presa è collegata allo. In realtà riflette lo stato dell'ultima operazione di invio/ricezione eseguita sul socket.
Se il socket è stato chiuso con le proprie azioni (smaltimento del socket, metodi di chiamata per la disconnessione), Socket.Connected
restituirà false
. Se la presa è stata disconnessa con altri mezzi, la proprietà restituirà true
fino al prossimo tentativo di inviare o ricevere informazioni, a quel punto verrà lanciato uno SocketException
o ObjectDisposedException
.
È possibile controllare la proprietà dopo che si è verificata l'eccezione, ma non è affidabile prima.
La migliore il modo è semplicemente di avere il client che invia un PING ogni X secondi e che il server presume che sia disconnesso dopo non averne ricevuto uno per un po '.
Ho riscontrato lo stesso problema riscontrato quando si utilizzavano i socket, e questo era l'unico modo per farlo. La proprietà socket.connected non è mai stata corretta.
Alla fine, però, sono passato a utilizzare WCF perché era molto più affidabile delle prese.
Come zendar scritto, è bello utilizzare il Socket.Poll
e Socket.Available
, ma è necessario prendere in considerazione che la presa non avrebbe potuto essere inizializzato in primo luogo. Questa è l'ultima informazione (credo) ed è fornita dalla proprietà Socket.Connected
.La versione rivista del metodo sarebbe simile a questa:
static bool IsSocketConnected(Socket s)
{
return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);
/* The long, but simpler-to-understand version:
bool part1 = s.Poll(1000, SelectMode.SelectRead);
bool part2 = (s.Available == 0);
if ((part1 && part2) || !s.Connected)
return false;
else
return true;
*/
}
ho fatto un metodo di estensione in base a this articolo di MSDN. Ecco come è possibile determinare se un socket è ancora connesso.
public static bool IsConnected(this Socket client)
{
bool blockingState = client.Blocking;
try
{
byte[] tmp = new byte[1];
client.Blocking = false;
client.Send(tmp, 0, 0);
return true;
}
catch (SocketException e)
{
// 10035 == WSAEWOULDBLOCK
if (e.NativeErrorCode.Equals(10035))
{
return true;
}
else
{
return false;
}
}
finally
{
client.Blocking = blockingState;
}
}
Seguendo i consigli da NibblyPig e zendar, mi si avvicinò con il codice qui sotto, che funziona su tutti i test che ho fatto. Alla fine ho avuto bisogno sia del ping che del sondaggio. Il ping mi consente di sapere se il cavo è stato disconnesso, altrimenti il livello fisico è stato interrotto (router spento, ecc.). Ma a volte dopo la riconnessione ottengo un RST, il ping è ok, ma lo stato TCP non lo è.
#region CHECKS THE SOCKET'S HEALTH
if (_tcpClient.Client.Connected)
{
//Do a ping test to see if the server is reachable
try
{
Ping pingTest = new Ping()
PingReply reply = pingTest.Send(ServeripAddress);
if (reply.Status != IPStatus.Success) ConnectionState = false;
} catch (PingException) { ConnectionState = false; }
//See if the tcp state is ok
if (_tcpClient.Client.Poll(5000, SelectMode.SelectRead) && (_tcpClient.Client.Available == 0))
{
ConnectionState = false;
}
}
}
else { ConnectionState = false; }
#endregion
La risposta accettata non sembra funzionare se si scollega il cavo di rete. O il server si blocca. O il tuo router si blocca. O se ti dimentichi di pagare la bolletta internet. Imposta le opzioni keep-alive TCP per una migliore affidabilità.
public static class SocketExtensions
{
public static void SetSocketKeepAliveValues(this Socket instance, int KeepAliveTime, int KeepAliveInterval)
{
//KeepAliveTime: default value is 2hr
//KeepAliveInterval: default value is 1s and Detect 5 times
//the native structure
//struct tcp_keepalive {
//ULONG onoff;
//ULONG keepalivetime;
//ULONG keepaliveinterval;
//};
int size = Marshal.SizeOf(new uint());
byte[] inOptionValues = new byte[size * 3]; // 4 * 3 = 12
bool OnOff = true;
BitConverter.GetBytes((uint)(OnOff ? 1 : 0)).CopyTo(inOptionValues, 0);
BitConverter.GetBytes((uint)KeepAliveTime).CopyTo(inOptionValues, size);
BitConverter.GetBytes((uint)KeepAliveInterval).CopyTo(inOptionValues, size * 2);
instance.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
}
}
// ...
Socket sock;
sock.SetSocketKeepAliveValues(2000, 1000);
Il valore temporale imposta il timeout in quanto i dati dall'ultimo invio. Quindi tenta di inviare e ricevere un pacchetto keep-alive. Se fallisce, ripete 10 volte (numero hardcoded da Vista AFAIK) nell'intervallo specificato prima di decidere che la connessione è morta.
Quindi i valori precedenti comporterebbero 2 + 10 * 1 = 12 secondi di rilevamento. Dopo ciò, qualsiasi operazione di lettura/scrittura/sondaggio dovrebbe fallire sul socket.
Scollego il socket con la forza (da uno strumento come la porta curr), ma non c'era la riconnessione automatica. – Eitan
Non si riconnetterà automaticamente. È solo un modo "migliore" per rilevare quando una connessione si interrompe senza inviare alcun dato. –
public static class SocketExtensions
{
private const int BytesPerLong = 4; // 32/8
private const int BitsPerByte = 8;
public static bool IsConnected(this Socket socket)
{
try
{
return !(socket.Poll(1000, SelectMode.SelectRead) && socket.Available == 0);
}
catch (SocketException)
{
return false;
}
}
/// <summary>
/// Sets the keep-alive interval for the socket.
/// </summary>
/// <param name="socket">The socket.</param>
/// <param name="time">Time between two keep alive "pings".</param>
/// <param name="interval">Time between two keep alive "pings" when first one fails.</param>
/// <returns>If the keep alive infos were succefully modified.</returns>
public static bool SetKeepAlive(this Socket socket, ulong time, ulong interval)
{
try
{
// Array to hold input values.
var input = new[]
{
(time == 0 || interval == 0) ? 0UL : 1UL, // on or off
time,
interval
};
// Pack input into byte struct.
byte[] inValue = new byte[3 * BytesPerLong];
for (int i = 0; i < input.Length; i++)
{
inValue[i * BytesPerLong + 3] = (byte)(input[i] >> ((BytesPerLong - 1) * BitsPerByte) & 0xff);
inValue[i * BytesPerLong + 2] = (byte)(input[i] >> ((BytesPerLong - 2) * BitsPerByte) & 0xff);
inValue[i * BytesPerLong + 1] = (byte)(input[i] >> ((BytesPerLong - 3) * BitsPerByte) & 0xff);
inValue[i * BytesPerLong + 0] = (byte)(input[i] >> ((BytesPerLong - 4) * BitsPerByte) & 0xff);
}
// Create bytestruct for result (bytes pending on server socket).
byte[] outValue = BitConverter.GetBytes(0);
// Write SIO_VALS to Socket IOControl.
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
socket.IOControl(IOControlCode.KeepAliveValues, inValue, outValue);
}
catch (SocketException)
{
return false;
}
return true;
}
}
- Copia la classe SocketExtensions al progetto
- chiamata la SetKeepAlive sulla presa - socket.SetKeepAlive (1000, 2);
- aggiungere un timer per controllare la funzione IsConnected
- 1. Verificare se il socket è in ascolto in C
- 2. Come posso verificare se un socket è ancora aperto?
- 3. Come verificare se il socket è chiuso in Boost.Asio?
- 4. Come verificare se il socket è ancora connesso?
- 5. Come verificare se un file è già aperto in C
- 6. Come verificare se un tipo è una stringa in C#?
- 7. Come verificare se è installato un servizio Windows in C#
- 8. Come posso verificare se un IP è attivo in java?
- 9. Verificare se un punto è in un rettangolo ruotato (C#)
- 10. Verificare se un valore è definito in un C enum?
- 11. Come verificare se un oggetto è definito?
- 12. Come verificare se una DLL COM è registrata in C#
- 13. Come verificare se la directory è nascosta in C#?
- 14. Come verificare se array vuoto in C
- 15. Come verificare se l'oggetto è un vettore
- 16. Come verificare se un DataSet è vuoto?
- 17. Verificare se è un oggetto
- 18. Come verificare se java.lang.reflect.Type è un Enum
- 19. Come verificare se un DataGridViewCheckBoxCell è verificato
- 20. Come verificare se un buffer è vuoto?
- 21. Come verificare se un puntatore è valido?
- 22. Come verificare se un contenitore è stabile
- 23. Verificare se i dati sono disponibili nei socket in python
- 24. Verificare se un metodo è un override?
- 25. Come verificare se un processo è in esecuzione utilizzando Delphi?
- 26. Verificare se un NSMutableDictionary è vuoto?
- 27. Come capire se un handle di file è un socket?
- 28. Come verificare/trovare se un elemento è in un DEQUE
- 29. In C#, come verificare se una stringa contiene un intero?
Penso che non sia necessario controllare la proprietà 'Available'. Secondo la pagina [MSDN] del metodo 'Poll' (http://msdn.microsoft.com/en-us/library/system.net.sockets.spocket.poll.aspx), restituisce true anche ** se i dati sono disponibile per la lettura **. –
Leggi di nuovo la documentazione, restituisce anche true se la connessione è chiusa o in attesa, quindi non sai se è attiva a meno che non controlli se un altro lato ti ha inviato alcuni dati. – zendar
Come one-liner: 'return! (Socket.Poll (1, SelectMode.SelectRead) && socket.Available == 0)' – kasperhj