Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TcpClient.EndConnect throws NullReferenceException when socket is closed

I am trying to connect to my server with a TcpClient.BeginConnect / TcpClient.EndConnect combo. However, some things don't work as they should.

The scenario is as follows:

  • Call to the TcpClient.BeginConnect
  • Server is intentionally offline (for testing purposes) - thus no connection can be made.
  • I close the application (client.Close() gets called in the process which closes the socket which in turn stops the async operation)
  • TcpClient connection callback method happens giving IAsyncResult
  • Call to the TcpClient.EndConnect method with the given IAsyncResult
  • NullReferenceException happens on EndConnect (?)
  • Since the last form (window) was closed, the app should exit - however it does not, at least not until BeginConnect operation completes (which is strange, as callback has already been called).

exception

What happens here is that a NullReferenceException is caught. As you can see from the picture above, neither client nor ar are null. The problem is that the MSDN documentation for the EndConnect does not mention the case in which this exception is thrown.

So basically, I have no idea what is going on. The problem is that I am forced to wait for the app to close (as if the connection operation still waits for a timeout). If a server is online, it connects and disconnects just fine.

What does NullReferenceException in this context mean? How to avoid BeginConnect operation to block the application closing in case the connection can't be established?


Additional notes (requested in comments):

Here is the code to create the client (client is a member variable:

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);
    }
}

Also the Close method:

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;
    }
}
like image 898
Kornelije Petak Avatar asked Jul 19 '11 21:07

Kornelije Petak


2 Answers

The NullReferenceException is probably due to TcpClient.Client being null.

If you were to follow the MSDN Example for TcpClient.BeginConnect and pass theTcpClient object as the state object:

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

This should handle the case when Close() is called before the Callback.

Going back to your problem - how long does it take for the application to eventually close?

like image 96
zrc210 Avatar answered Oct 18 '22 16:10

zrc210


This obviously a bug inside the TcpClient class. I have also faced it. TcpClient.Dispose may set Client field to null but EndConnect does not expect that.

like image 42
Lexey Avatar answered Oct 18 '22 15:10

Lexey