TcpClient.EndConnect генерирует исключение NullReferenceException при закрытом сокете - PullRequest
5 голосов
/ 20 июля 2011

Я пытаюсь подключиться к своему серверу с помощью TcpClient.BeginConnect / TcpClient.EndConnect комбо.Однако некоторые вещи не работают должным образом.

Сценарий таков:

  • Вызов на сервер TcpClient.BeginConnect
  • намеренно отключен (в целях тестирования) - таким образом, никакое соединение не может быть установлено.
  • Я закрываю приложение (client.Close() вызывается в процессе, закрывает сокет, который, в свою очередь, останавливает асинхронную операцию )
  • TcpClient соединение метод обратного вызова происходит, давая IAsyncResult
  • вызов метода TcpClient.EndConnect с указанным IAsyncResult
  • NullReferenceExceptionпроисходит в EndConnect (? )
  • Так как последняя форма (окно) была закрыта, приложение должно закрыться - однако этого не происходит, по крайней мере, пока операция BeginConnect не завершится (что странно, так как обратный вызов уже был вызван).

exception

Здесь происходит то, что NullReferenceException перехватывается.Как видно из рисунка выше, ни client, ни ar не являются null.Проблема в том, что в документации MSDN для EndConnect не упоминается случай, в котором выдается это исключение.

Так что в принципе я понятия не имею, что происходит.Проблема в том, что я вынужден ждать закрытия приложения (как будто операция подключения все еще ожидает тайм-аут). Если сервер подключен к сети, он просто подключается и отключается .

Что означает NullReferenceException в этом контексте ?Как избежать операции BeginConnect для блокировки закрытия приложения в случае невозможности установить соединение?


Дополнительные примечания ( запрашивается в комментариях ):

Вот код для создания клиента (клиент является переменной-членом:

public void Connect()
{
    try
    {
        lock (connectionAccess)
        {
            if (State.IsConnectable())
            {
                // Create a client
                client = new TcpClient();
                client.LingerState = new LingerOption(false, 0);
                client.NoDelay = true;

                State = CommunicationState.Connecting;

                client.BeginConnect(address, port, onTcpClientConnectionEstablished, null);
            }
            else
            {
                // Ignore connecting request if a connection is in a state that is not connectable 
            }
        }
    }
    catch
    {
        Close(true);
    }
}

Также метод Close:

public void Close(bool causedByError)
{
    lock (connectionAccess)
    {
        // Close the stream
        if (clientStream != null)
            clientStream.Close();

        // Close the gateway
        if (client != null)
            client.Close();

        // Empty the mailboxes
        incomingMailbox.Clear();
        outgoingMailbox.Clear();

        State = causedByError ? CommunicationState.CommunicationError : CommunicationState.Disconnected;
    }
}

Ответы [ 4 ]

1 голос
/ 20 июля 2011

Возможно, NullReferenceException из-за того, что TcpClient.Client является нулевым.

Если вы будете следовать примеру MSDN для TcpClient.BeginConnect и передать объект TcpClient в качестве объекта состояния:

 private void onConnEst(IAsyncResult ar)
 {
      try
      {
           TcpClient client = (TcpClient)ar.AsyncState;
           if(client!=null && client.Client!=null)
           {
                client.EndConnect(ar);
           }
      }
      catch(Exception ex){...}
 }

Это должно обрабатывать случай, когда Close() вызывается перед обратным вызовом.

Возвращаясь к вашей проблеме - сколько времени потребуется для закрытия приложения?

1 голос
/ 13 декабря 2012

Это, очевидно, ошибка внутри класса TcpClient.Я тоже с этим сталкивался.TcpClient.Dispose может установить в поле Client значение null, но EndConnect этого не ожидает.

0 голосов
/ 15 января 2015

Это известная ошибка .

Вы должны получить «ObjectDisposedException» вместо «NullReferenceException».

0 голосов
/ 20 июля 2011

У меня была похожая ошибка, и в итоге я использовал этот код.Я не уверен, будет ли он работать с интерфейсом IASyncResult, но может быть аналогичный способ выполнить эту проверку.Я заметил, что ваш ar.AsyncState == null, поэтому, возможно, попробуйте начать с него, т. Е. Будет ли он пустым при правильном подключении?

private void connConnectCompleted(AsyncCompletedEventArgs e)
{
    if (e.Error != null)
    {
        // Something didn't work...abort captain
        CloseSocket();
        Console.WriteLine(this.GetType().ToString() + @":Error connecting socket:" +  e.Error.Message);
        return;
    }
    // Do stuff with your connection
}

РЕДАКТИРОВАТЬ: Извините, я не понял, что я не опубликовал чтосгенерировал мой AsyncCompletedEventArgs, который больше связан с тем, что вы делаете.Вы увидите причину, по которой мне было интересно, что ar.AsyncState имеет значение null.

private void OnConnect(IAsyncResult asyncResult)
{
    if (OnConnectCompleted == null) return; // Check whether something is using this wrapper
    AsyncCompletedEventArgs args;
    try
    {
        Socket outSocket = (Socket) asyncResult.AsyncState;

        // Complete connection
        outSocket.EndConnect(asyncResult);

        args = new AsyncCompletedEventArgs(null);
        OnConnectCompleted(this, args);
    }
    catch (Exception e)
    {
        args = new AsyncCompletedEventArgs(e.Message);
        OnConnectCompleted(this, args);
    }
}
...