Когда вызывать BeginAccept для сокета - PullRequest
0 голосов
/ 26 ноября 2010

У меня есть следующий класс в службе Windows, который испытывает некоторые странные поведения выключения.Сервер время от времени отключается, только в журналах событий появляется только это сообщение, а в журналах трассировки нет сообщений: «Служба Broadcaster неожиданно прервана. Это произошло 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» завершается.Я не могу указать на это пальцем, но это просто пахнет неправильно.Должен ли сокет, который используется для прослушивания новых соединений, оставаться полем?Если нет, как бы вы назвали выключение позже?Это очень длительный (недели / месяцы) процесс.

Ответы [ 2 ]

1 голос
/ 26 ноября 2010

Размещенный код не вызывает необработанных исключений, которые могут отключить ваш сервер. Ну, это так, но только в Слушай.

Также не пишите Throw ex, он уничтожает исходную трассировку стека. Throw достаточно.

Что касается EndAccept / BeginAccept / HandleEvent, в этом нет ничего плохого.

0 голосов
/ 27 ноября 2010

Способ работы асинхронного Accept заключается в том, что вы обычно выдает BeginAccept сразу после принятия одного подключения, поэтому вы готовы к другой попытке входящего подключения.Я думаю, что процесс здесь довольно типичен - когда вы получаете обратный вызов для первого входящего соединения, вы запускаете EndAccept, чтобы завершить его, а затем еще один BeginAccept, чтобы подготовить сокет прослушивания к следующему.* Вы будете использовать сокет s для последующих операций ввода-вывода при первом входящем соединении, так что вам нужно его сохранить.логика, которая делает это, - установка clientSocket с использованием s в качестве параметра.

_socket - это та, которую ваш код использует для прослушивания всех входящих соединений.подробное описание того, как все это должно быть сделано здесь .

Я не вижу здесь никаких проблем с логикой обработки сокетов.Я предлагаю вам подключить к вашему сервису отладчик и попытаться выяснить, каков контекст во время выхода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...