Нужен более изящный шаблон для выключения TcpListener - PullRequest
2 голосов
/ 29 декабря 2011

У меня есть TcpListener, который при завершении работы заставляет все выполняющиеся клиенты генерировать приведенное ниже исключение при попытке вызвать EndAcceptTcpClient. Есть ли более изящный шаблон, который я могу использовать, чтобы позволить всем существующим клиентским подключениям завершиться до полного отключения TcpListener?

System.ObjectDisposedException: невозможно получить доступ к удаленному объекту. Имя объекта: 'System.Net.Sockets.Socket'. в System.Net.Sockets.Socket.EndAccept (IAsyncResult asyncResult) в System.Net.Sockets.TcpListener.EndAcceptTcpClient (IAsyncResult AsyncResult)

Вот пример настройки слушателя:

private TcpListener _requestListener;

requestListener = new TcpListener(endPoint);

requestListener.Start(1000);

requestListener.BeginAcceptTcpClient(ServiceRequestInstanceHandler, null);

Когда я пытаюсь закрыть слушателя, я вызываю следующее. Это то, что приводит к вышеупомянутому исключению.

if (_requestListener != null)
{
    _requestListener.Stop();
}

Вот пример кода, который обрабатывает обратные вызовы, которые в конечном итоге осуществляются путем вызова слушателей Stop() method

private void ServiceRequestInstanceHandler(IAsyncResult result)
{
    try
    {
        using (TcpClient client = _requestListener.EndAcceptTcpClient(result))
        {
            ProcessRequest(client);
            client.Close();
        }

        //Prepare to accept the next message
        _requestListener.BeginAcceptTcpClient(ServiceRequestInstanceHandler, null);
    }
    catch (Exception ex)
    {
        if (_logger.IsErrorEnabled)
            _logger.Error("An error occured while processing a service request. ", ex);
    }
}

1 Ответ

0 голосов
/ 29 декабря 2011

Полагаю, чтобы избежать ошибки, вам нужно передать ваш requestListener объект в BeginAcceptTcpClient, например, так:

requestListener.BeginAcceptTcpClient(ServiceRequestInstanceHandler, requestListener);

Для справки: http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.beginaccepttcpclient.aspx

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

private void ServiceRequestInstanceHandler(IAsyncResult result)
{
try
    {
        // You should probably check for a null result here, just in case
        if(result == null)
        {
            throw new Exception("Result is null, cannot continue");
        }
        using (TcpClient client = _requestListener.EndAcceptTcpClient(result))
        {
            // Remember this line returns immediately/does not block
            _requestListener.BeginAcceptTcpClient(ServiceRequestInstanceHandler, _requestListener);
            ProcessRequest(client);
            client.Close();
        }
    }
    catch (Exception ex)
    {
        if (_logger.IsErrorEnabled)
            _logger.Error("An error occured while processing a service request. ", ex);
    }
}

IIRC, асинхронная работа выполняется в отдельном потоке.

Примечание: Я не проверял вышеуказанный код, но он должен решить вашу проблему:)

НТН

...