0
votes

I am testing some tcp ip based server by my test client under .net in c#.

My test client class is some trivial async socket code:

public void Connect()
    {
        try
        {
            _tcpClient.BeginConnect(IPAddress, Port, OnConnectCallBack, null);
        }
        catch (Exception exc)
        {
            Debug.Assert(false, exc.Message);
        }
    }

private void OnConnectCallBack(IAsyncResult ar)
    {
        try
        {
            _tcpClient.EndConnect(ar);

        }
        catch (Exception exc)
        {
            Debug.WriteLine("Connection error: " + exc.Message);
        }
    }

_tcpClient is a TcpClient instance.

I try to make several (100) connections to the server at a time to stress test it. If I add some 50 msec sleep between calling connect, it works like a charm. But, when I try to connect in a foreach(...) iteration without adding sleep between connections, OnConnectCallBack throws the exception: A first chance exception of type 'System.NullReferenceException' occurred in System.dll. Connection error: Object reference not set to an instance of an object. Sometimes I get target machine refuse the connection exception.

After setting a breakpoint, I noticed it comes from _tcpClient: none of its methods and property values can be seen, all of them has null reference exception value, and its Client property is null.

at TestClient.OnConnectCallBack(IAsyncResult ar) C:...\TestClient.cs(82) at LazyAsyncResult.Complete(IntPtr userToken)
at ContextAwareResult.CompleteCallback(Object state)
at ExecutionContext.runTryCode(Object userData)
at RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at ContextAwareResult.Complete(IntPtr userToken)
at LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at LazyAsyncResult.InvokeCallback(Object result)
at QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at ThreadPoolWorkQueue.Dispatch()
at _ThreadPoolWaitCallback.PerformWaitCallback()

2
If you have no delay, is it possible that the TcpClient is busy in the BusyConnect() preventing the re-entrancy? The target machine error may be a result of the server not having enough queue slots waiting in the listen().Pekka
Hi Pekka! Thx! What do you mean as 'BusyConnect()'?Tom
Sorry. I meant BeginConnect(). Since the operation is asynchronous, it is possible that it is not safe to recall the method under all circumstances. You don't explain whether you are trying to stress test of functionally check the server. If it is the first, you could use separate instances of the TcpClient for each connection.Pekka
The reason is: to make stress test, exactly. I use separate TcpClients for each connection, that's why it is so strange...Tom
Please post the stack trace. I suspect that somehow you aren't using multiple TcpClient instances. The .NET framework has almost no bugs, especially after a decade of production hardening. Hard to believe you have found one with a trivial program.usr

2 Answers

2
votes

This behaviour is in my oppinion a result of the multiple calls of the asynchronous method BeginnConnect on the same instance of TcpClient without waiting for a established connection.

Depending of the intention of your stress test you have (at least) two possibilities:

  1. If you want to stress your application with multiple TcpClients you can create a List of TcpClients and iterate over this List to call BeginConnect. You should pass the instance of the TcpClient in the argument to have this instance in the callback function.

  2. To stress your application with fast connects, but only one at a time, call Connect instead of BeginnConnect. This will block the thread until the connection is established. Afterwards you call directly Close to disconnect. As this disposes the TcpClient you have to create a new instace before you call Connect again.

0
votes

Without seeing your code on how you're using this method (hint: post your code), it's hard to be certain of the problem.

Based on what you've explained, I'd guess that you're trying to use TcpClient across multiple concurrent operations. TcpClient doesn't support concurrent operations; you may use the BeginXXX and EndXXX pairs to perform operations asynchronously, but asynchronous processing does not equal concurrent processing.

Create an instance of TcpClient for each concurrent operation to solve your problem. This could be easily be achieved by creating one each time your loop runs.