none
"System.Net.Sockets.SocketException" abfangen RRS feed

  • Frage

  • Ich benutze zur Kommunikation einen TcpClient um eine Hostverbindung
    aufzubauen. Wenn nun der Host seinerseits die Verbindung beendet, gibt
    es eine "System.Net.Sockets.SocketException". Meine Frage ist nun, wie
    und wo ich die abfangen kann um meine state-machine intakt zu halten.
     
    Gruß,
    Hajü
     
    Dienstag, 6. September 2011 12:55

Antworten

  • Hallo Hans-J.,

    zum Beispiel so:

          catch (Exception exp)
          {
            Melde(exp.Message);
            if (tcpStream != null) tcpStream.Close();
            if (tcpClient != null) tcpClient.Close();
            NeuVerbinden(4);
            return;
          }
    

    aus Beispiel-Projekt-Download: http://dzaebel.net/Downloads/TcpClientServer4.zip

    aus Artikel:

    [Client-Server Kommunikation mit dem TcpClient und TcpListener]
    http://dzaebel.net/TcpClientServer.htm

     

    _____________________

    • Das wird langsam Kaffeesatzleserei, aber selbst wenn der Ansatz ok sein
    • sollte, gibt es für -2147467259 doch bestimmt einen symbolischen Wert?

    Will man genau den Fehler eines bestimmten Fehlercode behandeln, so ist das nicht unbedingt unsauber, wenn man sich auf dokumentierte Fehlercodes oder .NET-Enumerationen bezieht.
    In Deinem Fall (wenn denn die explizite Catch unbedingt erwünscht ist) würde ich lieber die SocketException catch-en und dann über den SocketErrorCode gehen. Also nicht GetHRForLastWin32Error benutzen, sondern etwas wie:

    mit folgenden dokumentierten Fehlercodes oder die SocketError-Enumeration:

          catch (SocketException exp)
          {
            // var nativeFehlerCode = exp.NativeErrorCode;
            if (exp.SocketErrorCode == SocketError.ConnectionRefused) // o.ä.
            {
    
            }
          }
    

    [Windows Sockets Error Codes (Windows)]
    http://msdn.microsoft.com/en-us/library/ms740668(VS.85).aspx

    Deine Fehlernummer ist ja hexadezimal geshiftet: '0x80004005' - aber das können verschiedenartike Fehler sein, deswegen ist etwas wie SocketError hier besser.
    Allgemein solltest Du Dir aber klar sein, dass auch andere Fehler auftreten können, die eigentlich ähnlich behandelt werden müssten, wobei man dann wieder bei der allgemeineren Exception oder SocketException ist.


    ciao Frank
    Samstag, 10. September 2011 10:18
  • -2147467259 ist hex 80004005 für den Mülleimer, wo alles abgekippt wird, was nicht einfach zuordenbar ist. Das ist leider so.
     
    Wenn es keine weitere InnerExeception gibt, hast Du wenig Chancen, etwas Sinnvolles zu erhalten.
     
    --
    Viele Gruesse
    Peter
    Samstag, 10. September 2011 11:55

Alle Antworten

  • Meine Frage ist nun, wie ... ich die abfangen kann

     

    Hallo Hans Hans-J. Ude,

    Kannst Du bitte Dein Problem deutlicher und völlig beschreiben? Relevanter Code zu posten wäre auch nicht schlecht.

    Tracing with System.Net

    Exceptions and Exception Handling (C# Programming Guide)

    Danke und Grüße,

    Robert

    Mittwoch, 7. September 2011 13:40
    Moderator
  • Hallo Robert,
     
    Am 07.09.2011 15:40, schrieb Robert Breitenhofer:
     
    > Kannst Du bitte Dein Problem deutlicher und völlig beschreiben?
    > Relevanter Code zu posten wäre auch nicht schlecht.
     
    Ich glaube speziellen code zu posten ist hier nicht hilfreich. Folgendes
    Szenario:
     
    1. Ich baue basierend auf einem TcpClient eine Verbindung zum Android
    Emulator auf (localhost, port 5554) und tausche mit dem Datan aus,
    funktioniert alles.
     
    2. Ich kille den Androiden bei bestehender Verbindung ohne laufenden
    Datenaustausch. Dann bekomme ich eine MessageBox mit diesem Text
     
    "Von der Übertragungsverbindung können keine Daten gelesen werden: Eine
    vorhandene Verbindung wurde vom Remotehost geschlossen."
     
    Im VS Debugger:
    Eine Ausnahme (erste Chance) des Typs "System.IO.IOException" ist in
    System.dll aufgetreten.
     
    Das Ereignis würde ich gerne abfangen, damit ich meine internen
    Variabelen entsprechen (zurück)setzen kann. Die ganze Kommunikation
    läuft asynchron, d.h. ich warte nicht explizit auf eine Antwort vom Host.
     
    Gruß,
    Hajü
     
     
    Mittwoch, 7. September 2011 15:11
  • Hallo Hans-J.,

    evtl. könnte folgendes gemeint sein, was in .NET 4.0 aber behoben ist:

    [c# - Catch unhandled SocketException during asynchronous HttpWebResponse read - Stack Overflow]
    http://stackoverflow.com/questions/1626499/catch-unhandled-socketexception-during-asynchronous-httpwebresponse-read

    [DeflateStream needs to handle exceptions from BeginRead on underlying streams | Microsoft Connect]
    https://connect.microsoft.com/VisualStudio/feedback/details/510564/deflatestream-needs-to-handle-exceptions-from-beginread-on-underlying-streams

     


    ciao Frank
    Freitag, 9. September 2011 05:37
  • Ich hab rausgefunden, dass bei einem hostseitigen Disconnect der
    ReadCallback() nochmal aufgerufen wird und die Messagebox erzeugt hat.
    An der Stelle rufe ich jetzt mein DoDisconnect() auf, der alles aufräumt
    und neu vorbereitet.
     
    public void ReadCallback(IAsyncResult ar)
    {
        int numRead = 0;
        try
        {
            if (Remote.Connected == true)
                numRead = Remote.GetStream().EndRead(ar);
        }
        catch (Exception ex)
        {
            // MessageBox.Show(ex.Message);
            Invoke(new Action(DoDisconnect));
        }
        .
        .
    } // End ReadCallback
     
    Die Frage ist jetzt, wie ich die Exception eindeutig identifizieren
    kann, und nur in dem speziellen Fall DoDisconnect() aufrufe.Aus der MSDN
    Doku und dem was ich sonst gefunden habe werde ich nicht so recht schlau.
     
    ich hab mal mit so Konstrukten wie
    if (ex.GetType().GUID.ToString() == "a164c0bf-67ae-3c7e-bc05-bfe24a8cdb62")
    rumexperimentiert, den GUID Wert habe ich aus dem Debugger. Aber das
    scheint mir alles vage und unsicher.
     
    Hajü
     
     
    Freitag, 9. September 2011 22:07
  • Am 10.09.2011 00:07, schrieb Hans-J. Ude:
    > ich hab mal mit so Konstrukten wie
    > if (ex.GetType().GUID.ToString() == "a164c0bf-67ae-3c7e-bc05-bfe24a8cdb62")
    > rumexperimentiert, den GUID Wert habe ich aus dem Debugger. Aber das
    > scheint mir alles vage und unsicher.
     
    oder so?
    catch (IOException ex)
    {
        if (Marshal.GetHRForException(ex.InnerException) == -2147467259)
            Invoke(new Action(DoDisconnect));
        else
            MessageBox.Show(ex.Message);
    }
     
    Das wird langsam Kaffeesatzleserei, aber selbst wenn der Ansatz ok sein
    sollte, gibt es für -2147467259 doch bestimmt einen symbolischen Wert?
     
    Hajü
     
     
    Freitag, 9. September 2011 23:11
  • Hallo Hans-J.,

    zum Beispiel so:

          catch (Exception exp)
          {
            Melde(exp.Message);
            if (tcpStream != null) tcpStream.Close();
            if (tcpClient != null) tcpClient.Close();
            NeuVerbinden(4);
            return;
          }
    

    aus Beispiel-Projekt-Download: http://dzaebel.net/Downloads/TcpClientServer4.zip

    aus Artikel:

    [Client-Server Kommunikation mit dem TcpClient und TcpListener]
    http://dzaebel.net/TcpClientServer.htm

     

    _____________________

    • Das wird langsam Kaffeesatzleserei, aber selbst wenn der Ansatz ok sein
    • sollte, gibt es für -2147467259 doch bestimmt einen symbolischen Wert?

    Will man genau den Fehler eines bestimmten Fehlercode behandeln, so ist das nicht unbedingt unsauber, wenn man sich auf dokumentierte Fehlercodes oder .NET-Enumerationen bezieht.
    In Deinem Fall (wenn denn die explizite Catch unbedingt erwünscht ist) würde ich lieber die SocketException catch-en und dann über den SocketErrorCode gehen. Also nicht GetHRForLastWin32Error benutzen, sondern etwas wie:

    mit folgenden dokumentierten Fehlercodes oder die SocketError-Enumeration:

          catch (SocketException exp)
          {
            // var nativeFehlerCode = exp.NativeErrorCode;
            if (exp.SocketErrorCode == SocketError.ConnectionRefused) // o.ä.
            {
    
            }
          }
    

    [Windows Sockets Error Codes (Windows)]
    http://msdn.microsoft.com/en-us/library/ms740668(VS.85).aspx

    Deine Fehlernummer ist ja hexadezimal geshiftet: '0x80004005' - aber das können verschiedenartike Fehler sein, deswegen ist etwas wie SocketError hier besser.
    Allgemein solltest Du Dir aber klar sein, dass auch andere Fehler auftreten können, die eigentlich ähnlich behandelt werden müssten, wobei man dann wieder bei der allgemeineren Exception oder SocketException ist.


    ciao Frank
    Samstag, 10. September 2011 10:18
  • Am 10.09.2011 12:18, schrieb Frank Dzaebel [MVP]:
    >
    > aus Beispiel-Projekt-Download:
     
    Das funktioniert leider bei mir nicht. Der grundsätzliche Unterschied
    besteht darin, dass du mit synchroner Kommunikation arbeitest und ich
    mit asynchroner. In deinem Beispiel kriegt der Client gar nicht mit,
    wenn der Server unerwartet beendet wird. Das mit
    if (Marshal.GetHRForException(ex.InnerException) == -2147467259) ...
    funktioniert bei mir ja, aber ich habe Zweifel das es auch zuverlässig
    funktioniert und diese magische -2147467259 ist auch unsauberer Stil.
     
    Gruß,
    Haü
     
    Samstag, 10. September 2011 11:50
  • -2147467259 ist hex 80004005 für den Mülleimer, wo alles abgekippt wird, was nicht einfach zuordenbar ist. Das ist leider so.
     
    Wenn es keine weitere InnerExeception gibt, hast Du wenig Chancen, etwas Sinnvolles zu erhalten.
     
    --
    Viele Gruesse
    Peter
    Samstag, 10. September 2011 11:55
  • Hallo Hans-J.,

    • In deinem Beispiel kriegt der Client gar nicht mit,
      wenn der Server unerwartet beendet wird.

    doch, wenn man auf OK drückt, was bei einem asynchronen Szenario einem regelmäßigen Pollen entspricht.

    • Das mit "if (Marshal.GetHRForException(ex.InnerException) == -2147467259) ...
      funktioniert bei mir ja, aber ich habe Zweifel das es auch zuverlässig
      funktioniert und diese magische -2147467259 ist auch unsauberer Stil.

    da hatte ich Dir schon empfohlen, die SocketException mit der SocketError-Enumeration über SocketErrorCode zu nehmen. Ich hatte bereits erwähnt, dass '0x80004005' verschiedenartige Fehler sein können, was aber in Deinem nicht unbedingt unsauber sein muss. Welcher Fehler kommt denn bei Dir im SocketErrorCode, wenn Du die SocketException catched? 80004005 ist schon auch dokumentiert, aber halt auch ein catch all. Die SocketError-Enumeration ist ja weit weg von unsauber.

     

     

     


    ciao Frank
    Samstag, 10. September 2011 13:05
  • Hallo Hans-J. Ude,

    Ich gehe davon aus, dass die Antworten Dir weitergeholfen haben.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert

    Montag, 19. September 2011 11:12
    Moderator
  • Am 19.09.2011 13:12, schrieb Robert Breitenhofer:
    > Ich gehe davon aus, dass die Antworten Dir weitergeholfen haben.
    > Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.
     
    Prinzipiell ja, allerdings bin ich mit diesem Konstrukt, insbesondere
    dieser magischen '-2147467259' nicht wirklich zufrieden. Statt dieser
    nichtssagenden Zahl hätte ich da lieber etwas Symbolisches, das ist
    unsauberer Stil so. Das ist genau 0x80004005, dafür muß doch irgenwo
    eine Konstante existieren. Und dieses Marshal.xyz(...) um an die Nummer
    zu kommen finde ich auch nicht gerade elegant.
     
    catch (IOException ex)
    {
       Exception e2 = ex.InnerException;
       if (Marshal.GetHRForException(e2) == -2147467259)
       {
          // irgendwas machen
       }
    }
     
    Dazu kommt noch, daß 0x80004005 eine SocketException im Allgemeinen
    bedeutet, die aber noch verschiedene Ursachen haben kann. Der Debugger
    sagt mir:
     
    +        e2    {System.Net.Sockets.SocketException (0x80004005): Eine vorhandene
    Verbindung wurde vom Remotehost geschlossen
       bei System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
       bei System.Net.Sockets.NetworkStream.EndRead(IAsyncResult
    asyncResult)}    System.Exception {System.Net.Sockets.SocketException}
     
    und der muss die Info doch auch irgendwo her haben. Ein
     
    catch (SocketException ex)
    { ... }
     
    funktioniert überigens überhaupt nicht, wird niemals angesprungen.
    Stattdessen wird das Progamm einfach sang- und klanglos beendet.
     
    Fazit: Das funktioniert alles nur scheinbar, aber nicht wirklich.
     
    Gruß,
    Hajü
     
    Montag, 19. September 2011 13:14