[英]When to call BeginAccept on a socket
我在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,然后完成與“客戶端套接字”的工作。 我不能將手指放在上面,但這聞起來不正確。 用於偵聽新連接的套接字是否應該保留為字段? 如果沒有,您以后怎么稱呼關機? 這是一個非常長時間(幾周/幾個月)的過程。
發布的代碼不會導致任何未處理的異常,這些異常可以關閉服務器。 是的,但是只有在Listen中。
另外,不要寫Throw ex
,它會破壞原始的堆棧跟蹤。 Throw
夠了。
至於EndAccept / BeginAccept / HandleEvent,這沒有什么錯。
異步Accept
工作方式是,通常在接受一個連接后立即發出BeginAccept
,因此您准備好進行另一個傳入的連接嘗試。 我認為這里的流程非常典型-當您獲得第一個傳入連接的回調時,發出EndAccept
來完成它,然后發出另一個BeginAccept
來使偵聽套接字為下一個做好准備。
您將在第一個傳入連接上將套接字s
用於后續的I / O,因此您需要保持該狀態。 執行此操作的邏輯是使用s
作為參數設置clientSocket
。
_socket
是您的代碼用來偵聽所有傳入連接的代碼。
還有的這是怎么應該做一個詳細的說明這里 。
我在這里看不到套接字處理邏輯的任何問題。 我建議您將調試器附加到服務中,並嘗試確定退出時的上下文。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.