C# – Verbindungsstatus eines Sockets feststellen – Teil 2

Ich schrieb schon zuvor einmal darüber, wie ich den Verbindungsstatus eines C#-Sockets überprüfe. Während der Testphase eines neuen Projekts, bei dem ich viele Mobilgeräte gleichzeitig über verschiedene Mobilfunktechnologien steuere, musste ich periodisch überprüfen, ob die verbundenen Clients überhaupt noch ansprechbar waren oder nicht. Also nutzte ich meine erprobte IsConnected-Methode und staunte nicht schlecht, als mir Code steif und fest behauptete, dass meine Verbindung noch bestünde, obwohl die Gegenstelle zu Testzwecken komplett ausgeschaltet wurde. Ich konnte sogar Daten in den Socket schreiben, ohne dass es Fehler hagelte. Klasse.

Ich erspare euch jetzt die wortreiche Beschreibung wie ich tagelang auf den Code starrte und meine Fingernägel rillen im Tisch hinterließen und mache es kurz: Erst nachdem ich das KeepAlive-Sendeintervall des Sockets drastisch heruntersetzte, funktionierte auch wieder meine IsConnected-Überprüfung wieder.

Hierzu fand ich im Internet die folgende Extension-Methode die, einmal im Namespace geladen, ihre Funktionalität jedem Socket-Objekt zur Verfügung stellt.

namespace System.Net.Sockets
{
  public static class SocketExtensions
  {
    private const int BytesPerLong = 4; // 32 / 8
    private const int BitsPerByte = 8;

    /// <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.Tcp, SocketOptionName.KeepAlive, true);
        socket.IOControl(IOControlCode.KeepAliveValues, inValue, outValue);
      }
      catch (SocketException e)
      {
        Console.WriteLine("Failed to set keep-alive: {0} {1}", e.ErrorCode, e);
        return false;
      }

      return true;
    }
  }
}

Die Benutzung des Codes ist sehr einfach:

//Create socket
var _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//Connect to any host
_socket.Connect(IPAddress.Parse("127.0.0.1"), 80);
//Set KeepAlive
_socket.SetKeepAlive(250, 100);

Mein Fazit?  Ich muss dringend von den Sockets wegkommen und etwas nutzen das mehr „High-level“ ist. Wenn ich weiterhin mit Sockets arbeite ist das einzige was „High-level“ ist nur mein Blutdruck.

Kolja Engelmann

Technikfan, Freizeitprogrammierer, selbsternannter Toolking und vermutlich größter Drachenfan Deutschlands blogged hier die Lösungen zu IT-Problemen die ihm über den Weg laufen, kleine Softwaretools, nostalgische Anfälle und missbraucht das Ganze gern auch mal als privates Tagebuch und Fotoalbum.

Das könnte dich auch interessieren …

Eine Antwort

  1. Brian Dahl sagt:

    Ich habe auch das schon probiert mit wenig erfolg, ich sehe zwar wenn ich die andere Seite vom Netz nehme im Wireshark das er es aufgibt weiter die KeepAlive Message zusenden, doch ich bekomme das im Programm nicht mit. Wenn ich den Socket mit Connected abfrage behauptet er immer das er Connected sei…

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert