wake-up-neo.com

Wie kann ich überprüfen, ob eine Steckdose in C # angeschlossen/getrennt ist?

Wie können Sie überprüfen, ob ein Netzwerk-Socket (System.Net.Sockets.Socket) noch angeschlossen ist, wenn der andere Host Ihnen kein Paket sendet, wenn er die Verbindung trennt (z. B. weil er die Verbindung nicht richtig hergestellt hat)?

56
lesderid

Als Paul Turner antwortete Socket.Connected kann in dieser Situation nicht verwendet werden. Sie müssen die Verbindung jedes Mal abfragen, um festzustellen, ob die Verbindung noch aktiv ist. Dies ist der Code, den ich verwendet habe:

bool SocketConnected(Socket s)
{
    bool part1 = s.Poll(1000, SelectMode.SelectRead);
    bool part2 = (s.Available == 0);
    if (part1 && part2)
        return false;
    else
        return true;
}

Es funktioniert so:

  • s.Poll gibt true zurück, wenn
    • verbindung ist geschlossen, zurückgesetzt, beendet oder anstehend (dh keine aktive Verbindung)
    • verbindung ist aktiv und es stehen Daten zum Lesen zur Verfügung
  • s.Available gibt die Anzahl der zum Lesen verfügbaren Bytes zurück
  • wenn beide wahr sind:
    • es sind keine Daten zum Lesen verfügbar, daher ist die Verbindung nicht aktiv
87
zendar

Wie zendar schrieb, ist es nett, Socket.Poll und Socket.Available zu verwenden, aber Sie müssen berücksichtigen, dass der Socket möglicherweise nicht initialisiert wurde. Dies ist die letzte (glaube ich) Information, die von der Socket.Connected-Eigenschaft bereitgestellt wird. Die überarbeitete Version der Methode würde ungefähr so ​​aussehen:

 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;

*/
    }
23
Automatico

Die Eigenschaft Socket.Connected sagt Ihnen, ob ein Socket denkt, dass er verbunden ist. Sie spiegelt tatsächlich den Status der letzten Sende-/Empfangsoperation wider, die an dem Socket ausgeführt wurde.

Wenn der Socket durch Ihre eigenen Aktionen geschlossen wurde (Entsorgen des Sockets, Aufrufen von Methoden zum Trennen der Verbindung), gibt Socket.Connectedfalse zurück. Wenn der Socket auf andere Weise getrennt wurde, gibt die Eigenschaft true zurück, bis Sie das nächste Mal versuchen, Informationen zu senden oder zu empfangen. Dann wird entweder eine SocketException oder ObjectDisposedException geworfen.

Sie können die Eigenschaft überprüfen, nachdem die Ausnahmebedingung aufgetreten ist, sie ist jedoch zuvor nicht zuverlässig.

13
Paul Turner

Die akzeptierte Antwort scheint nicht zu funktionieren, wenn Sie das Netzwerkkabel abziehen. Oder der Server stürzt ab. Oder Ihr Router stürzt ab. Oder wenn Sie vergessen, Ihre Internetrechnung zu bezahlen. Legen Sie die Keep-Alive-Optionen TCP für eine höhere Zuverlässigkeit fest.

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);

Der Zeitwert legt das Zeitlimit seit dem letzten Senden der Daten fest. Dann versucht es, ein Keep-Alive-Paket zu senden und zu empfangen. Wenn dies fehlschlägt, wiederholt es 10 Mal (Nummer seit Vista AFAIK fest codiert) in dem angegebenen Intervall, bevor entschieden wird, dass die Verbindung nicht aktiv ist.

Die obigen Werte würden also zu einer Erkennung von 2 + 10 * 1 = 12 Sekunden führen. Danach sollten alle Lese-, Schreib- und Abfragevorgänge auf dem Socket fehlschlagen.

4
toster-cx

Ich habe eine Erweiterungsmethode basierend auf this MSDN-Artikel erstellt.

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;
    }
}
3
Kim Ki Won

Dem Ratschlag von NibblyPig und zendar folgend, habe ich den folgenden Code gefunden, der bei jedem von mir durchgeführten Test funktioniert. Am Ende brauchte ich sowohl den Ping als auch die Umfrage. Der Ping informiert mich, wenn das Kabel getrennt wurde oder die physikalische Schicht anderweitig unterbrochen wurde (Router ausgeschaltet usw.). Aber manchmal bekomme ich nach dem Verbindungsaufbau ein RST, der Ping ist in Ordnung, der TCP-Status jedoch nicht.

#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
1
M Granja
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;
    }
}
  1. Kopieren Sie die SocketExtensions-Klasse in Ihr Projekt
  2. Rufen Sie das SetKeepAlive an Ihrer Steckdose auf. SocketKeepAlive (1000, 2);
  3. Fügen Sie einen Timer hinzu, um die IsConnected-Funktion zu überprüfen
1
Amir Twito

Der beste Weg ist einfach, dass Ihr Client alle X Sekunden einen PING sendet und der Server davon ausgeht, dass die Verbindung unterbrochen wird, nachdem er eine Zeit lang keine Verbindung erhalten hat.

Ich bin bei der Verwendung von Sockets auf dasselbe Problem gestoßen, und dies war die einzige Möglichkeit, dies zu tun. Die Eigenschaft socket.connected war nie korrekt.

Am Ende habe ich jedoch auf WCF umgestellt, weil es viel zuverlässiger war als Steckdosen.

1
NibblyPig

Wie Alexander Logger in der Antwort von zendar wies, muss man etwas senden, um ganz sicher zu sein. Wenn Ihr verbundener Partner überhaupt über diesen Socket liest, können Sie folgenden Code verwenden.

bool SocketConnected(Socket s)
{
  // Exit if socket is null
  if (s == null)
    return false;
  bool part1 = s.Poll(1000, SelectMode.SelectRead);
  bool part2 = (s.Available == 0);
  if (part1 && part2)
    return false;
  else
  {
    try
    {
      int sentBytesCount = s.Send(new byte[1], 1, 0);
      return sentBytesCount == 1;
    }
    catch
    {
      return false;
    }
  }
}

Aber selbst dann kann es einige Sekunden dauern, bis ein defektes Netzwerkkabel oder ähnliches erkannt wird.

0
Jrabauer