2010-11-26 60 views
0

我在Windows服務中遇到了一些不同的奇怪關機行爲中的以下類。服務器不時關閉,事件日誌中只有這條消息,跟蹤日誌中沒有消息,「Broadcaster服務意外終止,它已經完成了1次。」關於這個類脫穎而出對我何時調用套接字上的BeginAccept

Public Class ServerSocket 
    Implements IServerSocket 

    Public Event ClientConnected(ByVal sender As Object, ByVal e As EventArgs(Of IClientSocket)) Implements IServerSocket.ClientConnected 

    Private _socket As Socket 
    Private ReadOnly _settings As IBroadcasterServiceSettingsSection 
    Private ReadOnly _traceSource As ITraceSource 

    Public Sub New() 
     Me.New(BroadcasterServiceSettingsSection.GetSection, BroadcasterTraceSource.Instance) 
    End Sub 

    Public Sub New(ByVal settings As IBroadcasterServiceSettingsSection, ByVal traceSource As ITraceSource) 
     _settings = settings 
     _traceSource = traceSource 
    End Sub 

    Public Sub Listen() Implements IServerSocket.Listen 
     Dim endPoint As New IPEndPoint(System.Net.IPAddress.Parse(_settings.BroadcasterIPAddress), _settings.BroadcasterPortNumber) 
     Try 
      _socket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) 
      _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1) 
      _socket.Bind(endPoint) 
      _socket.Listen(SocketOptionName.MaxConnections) 
      _socket.BeginAccept(New AsyncCallback(AddressOf AcceptCallback), Nothing) 
      _traceSource.TraceInformation("ServerSocket listening for new clients.") 
     Catch ex As Exception 
      _traceSource.TraceCritical("ServerSocket caughtException trying to wait for a new client.") 
      Throw ex 
     End Try 
    End Sub 

    ''' <summary> 
    ''' First attempts to shutdown the socket to clean up any remaining data left to send or receive. Then closes 
    ''' the socket to release all connections and clean up unmanaged resources. See also <seealso cref="System.Net.Sockets.Socket.Shutdown">Socket.Shutdown</seealso> 
    ''' and <seealso cref="System.Net.Sockets.Socket.Close">Socket.Close</seealso> 
    ''' </summary> 
    Public Sub Close() Implements IServerSocket.Close 
     Try 
      _socket.Shutdown(SocketShutdown.Both) 
     Catch ex As Exception 
      _traceSource.TraceEvent(TraceEventType.Error, "Shutting down Server Socket caused an exception.", ex.Message, ex.StackTrace) 
     End Try 

     Try 
      _socket.Close() 
     Catch ex As Exception 
      _traceSource.TraceEvent(TraceEventType.Error, "Closing the Server Socket caused an exception.", ex.Message, ex.StackTrace) 
     End Try 

     _traceSource.TraceEvent(TraceEventType.Information, "ServerSocket closed.") 
    End Sub 

    Private Sub AcceptCallback(ByVal ar As IAsyncResult) 
     Dim s As Socket = Nothing 

     Try 
      s = _socket.EndAccept(ar) 
     Catch ex As Exception 
      _traceSource.TraceInformation("ServerSocket caught exception trying to get new socket for client.", ex.Message, ex.StackTrace) 
     End Try 

     Try 
      ' call the begin accept as soon as possible so that I can get the next incoming client 
      _socket.BeginAccept(New AsyncCallback(AddressOf AcceptCallback), Nothing) 
     Catch ex As Exception 
      _traceSource.TraceEvent(TraceEventType.Critical, "ServerSocket caughtException trying to wait for a new client.", ex.Message, ex.StackTrace) 
     End Try 

     Try 
      If s IsNot Nothing Then 
       Dim clientSocket As IClientSocket = New ClientSocket(s) 
       OnClientConnected(New EventArgs(Of IClientSocket)(clientSocket)) 
      End If 
     Catch ex As Exception 
      _traceSource.TraceEvent(TraceEventType.Critical, "9/23 Review: " + ex.ToString()) 
     End Try 
    End Sub 

    Private Sub OnClientConnected(ByVal e As EventArgs(Of IClientSocket)) 
     RaiseEvent ClientConnected(Me, e) 
    End Sub 
End Class 

的一件事是_socket.EndAccept被調用後立即_socket.BeginAccept被調用,並與「客戶端套接字」工作完成之後。我不能把手指放在上面,但這只是不正確的。應該將用於監聽新連接的套接字保存爲字段嗎?如果沒有,稍後您會如何調用關機?這是一個非常長時間(周/月)的過程。

+0

在每個小時結束時捕獲您的內存使用情況。 – 2010-11-27 15:22:52

回答

0

異步Accept的工作方式是,您通常在接受一個連接後立即發出BeginAccept,因此您已準備好接受另一個傳入連接嘗試。我認爲這裏的流程非常典型 - 當您獲得第一個傳入連接的回調時,您會發出EndAccept來完成它,然後發出另一個BeginAccept以保持監聽套接字準備好接下來。

對於第一個傳入連接上的後續I/O,您將使用套接字s,因此您確實需要保持這一點。這樣做的邏輯是使用s作爲參數的clientSocket的設置。

_socket是您的代碼用來偵聽所有傳入連接的代碼。

詳細說明了這是如何完成的here

我在這裏看不到任何問題的套接字處理邏輯。我建議你在你的服務中附加一個調試器,並試着找出退出時的上下文。

+0

附加調試器是一個catch-22。該服務不會很快失敗。它可能會運行4個星期或4個小時,然後突然間就會消失。錯誤日誌中沒有錯誤,跟蹤日誌中沒有錯誤。 – 2010-11-27 15:20:01

1

發佈的代碼不會導致任何可以關閉服務器的未處理的異常。嗯,它的確如此,但只有在Listen中。

另外,不要寫Throw ex,它破壞了原始堆棧跟蹤。 Throw就夠了。

至於EndAccept/BeginAccept/HandleEvent,沒有什麼錯。