我在Windows服务中遇到以下类,这些类遇到一些不同的奇怪关机行为。服务器不时关闭,事件日志中只显示此消息,跟踪日志中没有消息,“广播服务意外终止。已经完成了1次。”
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,然后完成“Client Socket”的工作。我不能把手指放在上面,但这听起来不对劲。用于侦听新连接的套接字是否应保留为字段?如果没有,你以后怎么称之为关机呢?这是一个非常长的(数周/月)过程。
答案 0 :(得分:1)
发布的代码不会导致任何可能导致服务器关闭的未处理异常。嗯,确实如此,但仅限于听。
另外,不要写Throw ex
,它会破坏原始的堆栈跟踪。 Throw
就足够了。
对于EndAccept / BeginAccept / HandleEvent,没有任何问题。
答案 1 :(得分:0)
异步Accept
的工作方式是您通常在接受一个连接后立即发出BeginAccept
,因此您已准备好进行另一次传入连接尝试。我认为这里的流程非常典型 - 当您获得第一个传入连接的回调时,您发出EndAccept
来完成它,然后发出另一个BeginAccept
以保持侦听套接字为下一个做好准备。 / p>
您将在第一个传入连接上使用套接字s
进行后续I / O,因此您需要保留它。这样做的逻辑是使用clientSocket
作为参数设置s
。
_socket
是您的代码用来侦听所有传入连接的那个。
详细描述了这一切应该如何完成here。
我在这里看不到套接字处理逻辑的任何问题。我建议您将调试器附加到您的服务中,并尝试确定退出时的上下文。