¿Cómo se puede verificar si un socket de red (System.Net.Sockets.Socket) aún está conectado si el otro host no le envía un paquete cuando se desconecta (por ejemplo, porque se desconectó sin gracia)?¿Cómo verificar si un socket está conectado/desconectado en C#?
Respuesta
Como Paul Turner responde Socket.Connected
no se puede utilizar en esta situación. Necesita sondear la conexión cada vez para ver si la conexión aún está activa. Este es el código utilicé:
bool SocketConnected(Socket s)
{
bool part1 = s.Poll(1000, SelectMode.SelectRead);
bool part2 = (s.Available == 0);
if (part1 && part2)
return false;
else
return true;
}
Funciona así:
s.Poll
devuelve verdadero si- conexión se cierra, reset, terminado o en espera (es decir, sin conexión activa)
- conexión está activa y no hay datos disponibles para la lectura
s.Available
rendimientos número de bytes disponibles para su lectura- si ambas son verdaderas:
- no hay datos disponibles para leer así que la conexión no está activa
Uso Socket.Connected
Propiedad.
Ten en cuenta que incluso si Socket.Connected devuelve verdadero, el enchufe no esté conectado. Si es falso, definitivamente no está conectado. – nos
La propiedad Socket.Connected
le dirá si un conector piensa que está conectado. En realidad, refleja el estado de la última operación de envío/recepción realizada en el socket.
Si el zócalo se ha cerrado por sus propias acciones (desechando el zócalo, llamando a métodos para desconectarlo), Socket.Connected
devolverá false
. Si el socket se ha desconectado por otros medios, la propiedad devolverá true
hasta que intente enviar o recibir información, en cuyo momento se lanzarán SocketException
o ObjectDisposedException
.
Puede verificar la propiedad después de que se haya producido la excepción, pero antes no era confiable.
La mejor es simplemente hacer que su cliente envíe un PING cada X segundos, y que el servidor asuma que está desconectado después de no haber recibido uno por un tiempo.
Me encontré con el mismo problema que cuando usaba sockets, y esta era la única forma en que podía hacerlo. La propiedad socket.connected nunca fue correcta.
Al final, cambié a usar WCF porque era mucho más confiable que los sockets.
Como escribió zendar, es bueno usar Socket.Poll
y Socket.Available
, pero debe tener en cuenta que es posible que el socket no se haya inicializado en primer lugar. Esta es la última (creo) información y la proporciona la propiedad Socket.Connected
.La versión revisada del método haría es como la siguiente:
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;
*/
}
hice un método de extensión basado en this artículo de MSDN. Así es como puede determinar si un socket todavía está conectado.
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;
}
}
Siguiendo el consejo de NibblyPig y zendar, me ocurrió con el código de abajo, que funciona en todas las pruebas que hice. Terminé necesitando tanto el ping como la encuesta. El ping me avisará si el cable se ha desconectado o si la capa física se ha interrumpido (enrutador apagado, etc.). Pero a veces, después de reconectarme obtengo un RST, el ping está bien, pero el estado tcp no.
#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 respuesta aceptada no parece funcionar si desenchufa el cable de red. O el servidor se cuelga. O su enrutador se bloquea. O si olvida pagar su factura de internet. Establezca las opciones TCP keep-alive para una mejor confiabilidad.
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);
El valor de tiempo establece el tiempo de espera desde que se enviaron los datos por última vez. Luego intenta enviar y recibir un paquete de mantenimiento de vida. Si falla, vuelve a intentar 10 veces (número codificado desde Vista AFAIK) en el intervalo especificado antes de decidir que la conexión está muerta.
De modo que los valores anteriores darían como resultado 2 + 10 * 1 = 12 segundos de detección. Después de eso, cualquier operación de lectura/lectura/encuesta fallará en el socket.
Desconecto el socket por la fuerza (desde una herramienta como el puerto curr), pero no hubo reconexión automática. – Eitan
No se reconectará automáticamente. Es solo una "mejor" forma de detectar cuándo cae una conexión sin enviar datos. –
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;
}
}
- Copiar la clase SocketExtensions a su proyecto
- Llame al SetKeepAlive en su zócalo - socket.SetKeepAlive (1000, 2);
- Añadir un temporizador para controlar el funcionamiento isConnected
- 1. ¿Cómo verificar si el socket todavía está conectado?
- 2. Compruebe si el socket está escuchando en C
- 3. ¿Cómo verificar si un objeto está definido?
- 4. ¿Cómo puedo verificar si todavía hay un socket abierto?
- 5. ¿Cómo puedo verificar si un socket está actualmente conectado en Java?
- 6. Cómo verificar si un DataGridViewCheckBoxCell está marcado
- 7. ¿Cómo puedo verificar si una IP está viva en Java?
- 8. ¿Cómo saber si el socket está abierto en PHP?
- 9. ¿Cómo comprobar si el socket está cerrado en Boost.Asio?
- 10. cómo verificar si un host está en su known_host ssh
- 11. Cómo verificar/encontrar si un artículo está en un DEQUE
- 12. Cómo verificar si una conexión de socket está activa en Boost :: asio?
- 13. C++: ¿cómo puedo verificar si el buffer cin está vacío?
- 14. Cómo verificar C# si la cuenta de usuario está activa
- 15. ¿Cómo puedo verificar si un JSON está vacío en NodeJS?
- 16. ¿Cómo puedo verificar si un filehandle está abierto en Perl?
- 17. iOS - ¿Cómo verificar si una NSOperation está en un NSOperationQueue?
- 18. ¿Cómo verificar si una fecha está en un rango determinado?
- 19. cómo verificar si un hash está vacío en perl
- 20. ¿Cómo verificar si un borde está en algún ciclo?
- 21. Verificar si datepicker está abierto
- 22. ¿Cómo verificar si un proceso se está ejecutando con Delphi?
- 23. Verificar si Solidworks está instalado?
- 24. Cómo verificar si una NSWindow está visible
- 25. C# ¿Verifica si el enchufe está desconectado?
- 26. ¿Cómo verificar si jQuery datepicker está vacío?
- 27. Cómo verificar si dynamic está vacío.
- 28. ¿Cómo verificar si sql_safe_updates está activado?
- 29. Cómo verificar si un valor de matriz profunda está presente
- 30. ¿Cómo puedo verificar si un valor está contenido en un vector? C++
Creo que no necesita verificar la propiedad 'Disponible'. De acuerdo con el método 'Poll' [página MSDN] (http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.poll.aspx), también devuelve true ** si los datos son disponible para leer **. –
Lea de nuevo la documentación, también devuelve verdadero si la conexión está cerrada o pendiente, por lo que no sabrá si está activa, a menos que compruebe si el otro lado le envió algunos datos. – zendar
Como una línea: 'return! (Socket.Poll (1, SelectMode.SelectRead) && socket.Available == 0)' – kasperhj