Website-Icon Digital Native

C# – Socket.Connected bringt mich um den Verstand, funktioniert nun aber

Manchmal braucht man echt viel Vorwissen über ein Thema…hat man es nicht möchte man am liebsten seine Maus aufessen. Ich arbeitete mit ein paar Sockets und war der kindlich-naiven Überzeugung, dass die .NET Property Connected mir auch tatsächlich ausgeben würde, ob mein Socket noch verbunden sei oder nicht. Nope, macht er nicht…jedenfalls nicht direkt.

.NET überprüft von sich aus nämlich nicht, ob die Verbindung die einem Socket zu Grunde liegt, noch besteht. Stattdessen zeigt Connected immer den letzten bekannten Status an, der zum Zeitpunkt der letzten Lese/Schreiboperation herrschte und behält diesen bei. So kann es also durch aus sein, dass die Verbindung komplett abbricht, z.B. durch ein gezogenes Kabel und Connected zeigt noch immer brav true an.

Setzt man sich mit hochrotem Kopf hin und liest sich in dieses Thema ein, stellt man fest, dass dieses Verhalten zwar unlogisch, aber durchaus korrekt ist. TCP ist in diesem Bereich sehr fehlertolerant und stört sich nicht daran, wenn mal eine Verbindung verloren geht. Die logische Verbindung zwischen den zwei Endpunkten könnte durchaus für längere Zeit physikalisch getrennt und irgendwann wieder hergestellt werden und die Verbindung würde weiterhin bestehen und auch genutzt werden können. Einzig ein Timeout (der je nach Betriebssystem anders ist) könnte ein darüber liegendes Programm darüber informieren, dass seine Verbindung nicht mehr besteht.

Schreibe ich in einen geschlossenen Socket, dann hagelt es natürlich Exceptions. Was kann ich also tun? Ich habe lange im Internet herumgegraben und es gibt wirklich viele verschiedene Lösungsversuche, die beinahe alle  wie der folgende erste Codeschnippsel aussehen, der versucht 0 Byte in den Socket zu schreiben  oder auf irgendwelche ankommenden Pakete zu lauschen.

/// <summary>
/// Checks the connection state
/// </summary>
/// <returns>True on connected. False on disconnected.</returns>
public bool IsConnected(Socket pSocket)
{
  if (pSocket.Connected)
  {
    if ((pSocket.Poll(0, SelectMode.SelectWrite)) && (!pSocket.Poll(0, SelectMode.SelectError)))
    {
      byte[] buffer = new byte[1];
      if (pSocket.Receive(buffer, SocketFlags.Peek) == 0)
      {
        return false;
      }
      else
      {
        return true;
      }
    }
    else
    {
      return false;
    }
  }
  else
  {
    return false;
  }
}

Leider funktionierte das in meinem Fall einfach mal gar nicht, weil von meiner Gegenstelle keine Daten gesendet werden, die in obiger Funktion hätten „empfangen“ werden können. Auch ein heruntersetzen des  TCP KeepAlive-Pakets Intervalls half hier nicht weiter.

Nach langem hin und her, bin ich auf die einfachste und hässlichste Methode zurückgesprungen: Ich versuche zu schreiben, fange alle Exceptions ab und erhalte daraus den Status meines Sockets.

/// <summary>
/// For whatever reason every single IsConnected-version I came up with was not working.
/// So this is the most elementary version, relying on exceptions
/// </summary>
/// <param name="pSocket"></param>
/// <returns>True if connected, else false</returns>
public static bool IsConnectedWithExceptions(Socket pSocket)
{
  try
  {
    pSocket.Send(new byte[0]);
    return true;
  }
  catch
  {
    return false;
  }
}

Hässlich, schlechter Code, ich hasse mich selbst dafür, aber macht verdammt nochmal was er soll!

Die mobile Version verlassen