2010-11-26 13 views
0

私は、いくつかの奇妙なシャットダウン動作が異なるWindowsサービスで、次のクラスを持っています。サーバーは、イベントログのこのメッセージだけで時折シャットダウンし、トレースログには「ブロードキャスターサービスが予期せず終了しました。この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

各時間の最後に、メモリ使用量をキャプチャします。 –

答えて

0

非同期Acceptの仕組みは、1つの接続を受け入れるとすぐにBeginAcceptを発行するため、別の着信接続の準備ができています。私はここの流れは非常に典型的なものだと思います。最初の着信接続のコールバックを取得したら、EndAcceptを発行してもう1つのBeginAcceptを発行して、次の着信ソケットを準備します。

最初の着信接続では、後で入出力するためにソケットsを使用します。そのため、それを回避する必要があります。それを行うロジックはclientSocketの設定で、sをパラメータとして使用します。

_socketは、すべての着信接続を待機するためにコードが使用するコードです。

これがどのように行われるのかの詳細な説明はhereです。

ここでソケット処理ロジックに問題はありません。私は、あなたのサービスにデバッガを付けて、終了時のコンテキストを解明することをお勧めします。

+0

デバッガのアタッチはcatch-22です。サービスはすぐに失敗しません。それは4週間または4時間実行することがありますし、青から消えるだけです。エラー・ログにエラーはなく、トレース・ログにもエラーはありません。 –

1

投稿されたコードは、サーバーをシャットダウンできる未処理の例外を発生させません。まあ、そうですが、Listenだけです。

また、Throw exも書き込まないで、元のスタックトレースを破棄します。 Throwで十分です。

EndAccept/BeginAccept/HandleEventについては、何も問題ありません。

関連する問題