tutorials.de Buch-Aktion 02/2012
ERLEDIGT
JA
ANTWORTEN
4
ZUGRIFFE
824
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    StehtimSchilf StehtimSchilf ist offline Mitglied Gold
    Registriert seit
    Oct 2003
    Beiträge
    114
    Hi Forum

    Ich habe einen .NET Windows Service der auf einem Socket horcht:

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
            Dim smtpPort as Integer = 2525
     
            Dim ipHostInfo As IPHostEntry = Dns.GetHostEntry(Dns.GetHostName())
            Dim localEndPoint As New IPEndPoint(ipHostInfo.AddressList(0), smtpPort)
     
            Dim listener As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
     
            listener.Bind(localEndPoint)
            listener.Listen(10)
     
            'blockierend
            Dim socket As Socket = listener.Accept()

    So das funktioniert bis jetzt eigentlich sauber (try-catch etc. weggelassen). Wenn ich nun meinen Service über die MMC restarte, dann erhalte ich Fehlermeldungen betreffend:
    Normalerweise darf jede Socketadresse (Protokoll, Netzwerkadresse oder Anschluss) nur jeweils einmal verwendet werden
    Also dachte ich mir, schliesse ich den Socket im Service-OnStop()-Event so etwas à la:
    Code :
    1
    2
    
                'listener.Disconnect(False)
                listener.Close()
    Doch damit erhalte ich nun eine Exception bei listener.accept():
    System.Net.Sockets.SocketException: Ein Blockierungsvorgang wurde durch einen Aufruf von WSACancelBlockingCall unterbrochen
    bei System.Net.Sockets.Socket.Accept()
    Wie schliesse ich denn nun den Socket richtig? Wenn ich den Service nur Stoppe, 2,3 Sekunden warte und dann wieder starte, dann funktioniert es ohne Fehlemeldungen. Einfach der Restart hat er nicht so gerne. Daher möchte ich eben die accept() unterbrechen. Wie geht das nach Kochbuch?

    cheerioh & thx
    SiS
     

  2. #2
    Avatar von Shakie
    Shakie Shakie ist offline Mitglied Diamant
    Registriert seit
    May 2004
    Ort
    Europa
    Beiträge
    2.002
    Ich denke das passt schon so. Mit dem Disconnect-Aufruf zwingst du die Accept-Methode, dass sie zurückkehrt. Da sie aber keinen Rückgabewert definieren kann, wirft sie eine Fehlermeldung.
    Eine SocketException kann aber auch andere Ursachen haben; um diese herauszufinden liefert dir die ErrorCode-Eigenschaft der SocketException genauere Informationen. Informationen zum ErrorCode findest du hier. Also wenn bei dir der Wert WSAEINTR=10004 im ErrorCode drin steht, dann kannst du die Fehlermeldung einfach ignorieren bzw. weißt, dass ein anderer Thread die Disconnect-Methode (oder Ähnliche) aufgerufen hat.
    P.S.: Bitte nimm das nicht 100%-ig für wahre Münze, habe nur MSDN gelesen, aber keine Erfahrung damit.
    Geändert von Shakie (23.06.10 um 19:54 Uhr)
     

  3. #3
    StehtimSchilf StehtimSchilf ist offline Mitglied Gold
    Registriert seit
    Oct 2003
    Beiträge
    114
    Hi Shakie

    Danke für Deine Links. Wie es scheint lässt sich das Problem genau so "umgehen".

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    Try
       listener.Bind(localEndPoint)
       listener.Listen(10)
     
       ' Start listening for connections.
       running = True
       While running
          ' zzzzzzzzzzz....
          Dim socket As Socket = listener.Accept()
     
          Dim session As New SMTPSession(socket)
            
          ' do session stuff
            
       End While 'ready for next message
     
    Catch e As Exception
       If System.Runtime.InteropServices.Marshal.GetLastWin32Error() = 10004 Then
           ' ignore error of blocking operation WSACancelBlockingCall
       Else
          ' do error handler stuff
       End If
    End Try

    cheerioh
    SiS
    Geändert von StehtimSchilf (25.06.10 um 10:29 Uhr)
     

  4. #4
    Avatar von Shakie
    Shakie Shakie ist offline Mitglied Diamant
    Registriert seit
    May 2004
    Ort
    Europa
    Beiträge
    2.002
    Ich würde die Fehlerbehandlung so gestalten:
    Code vbnet:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    Try
        ' ...
    Catch ex As Net.Sockets.SocketException
        If ex.ErrorCode <> 10004 Then
            ' Fehlerbedhanlung für SocketExceptions
        End If
    Catch ex As Exception
        ' Fehlerbedhanlung für andere Exceptions
    End Try
    Das erscheint mir hübscher als der Aufruf von Marshal.GetLastWin32Error. Und ich vermute der Zugriff auf die ErrorCode-Eigenschaft sollte schneller sein als der Aufruf von Marshal.GetLastWin32Error.
     

  5. #5
    Cromon Cromon ist offline Mitglied Brillant
    Registriert seit
    Apr 2008
    Beiträge
    819
    GetLastWin32Error dürfte kaum mehr Aufwand sein, aber möglicherweise nicht funktionieren. Der CLR-Host selbst ruft ja ständig Windows-Funktionen auf (schon alleine zwischen accept und dem Abfangen der Exception wohl einige), welche wiederum fs:[0x34] (Last Error Code) verändern. Deshalb macht ja auch Marshal.GetLastWin32Error auch nicht das, was GetLastError im unverwalteten macht
    Code asm:
    1
    2
    3
    4
    
    _GetLastError@0:
    mov         eax,dword ptr fs:[00000018h]  
    mov         eax,dword ptr [eax+34h]  
    ret

    sondern es wird eine Variable abgefragt, welche für jeden Thread den letzten von aussen aufgerufenen Errorcode enthält. Das funktioniert jedoch nur, wenn die Funktion, von welcher du den Errorcode wissen möchtest auch das Attribut SetLastError(true) hat. Nur dann speichert der CLR-Host den Code der Funktion. Bedenkt man nun, dass ErrorCode ein Property ist, so ist beides nur ein simpler Funktionsaufruf, welcher einen Wert einer Variablen zurückgibt. Performance dürfte daher praktisch identisch sein (abhängig vom jeweiligen Overhead), aber obs funktioniert kann man so nicht sagen. Marshal.GetLastWin32Error ist eigentlich (nur) für Verwendung nach P-Invoke gedacht.
     

Ähnliche Themen

  1. Fenster mit anderem Thread öffnen
    Von Knight_Rider im Forum .NET Windows Forms
    Antworten: 2
    Letzter Beitrag: 05.01.08, 19:07
  2. AsyncSocket in Thread schliessen
    Von Dipsi im Forum VisualStudio & MFC
    Antworten: 3
    Letzter Beitrag: 13.03.07, 07:06
  3. Socket schliessen
    Von MaLb im Forum Java
    Antworten: 4
    Letzter Beitrag: 29.12.06, 11:28
  4. Socket schliessen
    Von DerKleineVomSee im Forum Java
    Antworten: 12
    Letzter Beitrag: 13.06.06, 15:52