簡體   English   中英

何時在套接字上調用BeginAccept

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM