//____________________________________________________________________________
        private void ProcessDisconnectAndCloseSocket(SocketAsyncEventArgs receiveSendEventArgs)
        {
            DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken;

            if (Program.watchProgramFlow == true)
            {
                Program.testWriter.WriteLine("\r\nProcessDisconnect(), id = " + receiveSendToken.TokenId);
            }

            if (receiveSendEventArgs.SocketError != SocketError.Success)
            {
                if (Program.watchProgramFlow == true)   //for testing
                {
                    Program.testWriter.WriteLine("ProcessDisconnect ERROR, id " + receiveSendToken.TokenId);
                }
                else if (Program.writeErrorsToLog == true)
                {
                    Program.testWriter.WriteLine("ProcessDisconnect ERROR, id " + receiveSendToken.TokenId);
                }
            }

            if (Program.watchData == true)
            {
                Program.testWriter.WriteLine(ShowData(receiveSendToken));
            }

            //This method closes the socket and releases all resources, both
            //managed and unmanaged. It internally calls Dispose.
            receiveSendEventArgs.AcceptSocket.Close();

            //for testing
            Int32 sCount = receiveSendToken.theDataHolder.NumberOfMessagesSent;

            //create an object that we can write data to.
            receiveSendToken.CreateNewDataHolder();

            // It is time to release this SAEA object.
            this.poolOfRecSendEventArgs.Push(receiveSendEventArgs);

            //Count down the number of connected clients as they disconnect.
            Interlocked.Decrement(ref this.clientsNowConnectedCount);

            Interlocked.Increment(ref this.numberOfConnectionsFinishedSuccessfully);
            Interlocked.Increment(ref this.totalNumberOfConnectionsFinished);
            this.theMaxConnectionsEnforcer.Release();

            if (Program.showConnectAndDisconnect == true)
            {
                Program.testWriter.WriteLine(receiveSendToken.TokenId + " id disconnected. " + sCount + " = sent message count. " + this.clientsNowConnectedCount + " client connections to server from this machine. " + this.totalNumberOfConnectionsFinished + " clients finished.\r\n");
            }
            //If all of the clients have finished sending
            //and receiving all of their messages, then we
            //need to finish.
            if (this.totalNumberOfConnectionsFinished == this.socketClientSettings.ConnectionsToRun)
            {
                this.completedAllTests = true;
                FinishTest();
            }
        }
        //____________________________________________________________________________
        // Initializes the client by preallocating reusable buffers and
        // context objects (SocketAsyncEventArgs objects).
        // It is NOT mandatory that you preallocate them or reuse them.
        // In fact, you would probably NOT normally do this on a client.
        // But, for testing we want to be able to throw a lot of connections at
        // our socket server from a LAN. And this is a way to do it.
        //
        private void Init()
        {
            if (Program.watchProgramFlow == true)   //for testing
            {
                Program.testWriter.WriteLine("Init method");
                Program.testWriter.WriteLine("Creating connect SocketAsyncEventArgs pool");
            }

            SocketAsyncEventArgs connectEventArg;

            // preallocate pool of SocketAsyncEventArgs objects for connect operations
            for (int i = 0; i < this.socketClientSettings.MaxConnectOps; i++)
            {
                connectEventArg = CreateNewSaeaForConnect(poolOfConnectEventArgs);

                // add SocketAsyncEventArg to the pool
                this.poolOfConnectEventArgs.Push(connectEventArg);
            }

            if (Program.watchProgramFlow == true)   //for testing
            {
                Program.testWriter.WriteLine("");
            }

            // Allocate one large byte buffer block, which all I/O operations will use a piece of.
            //This gaurds against memory fragmentation.
            this.bufferManager.InitBuffer();


            //The pool that we built ABOVE is for SocketAsyncEventArgs objects that do
            // connect operations. Now we will build a separate pool for
            //SocketAsyncEventArgs objects that do receive/send operations.
            //One reason to separate them is that connect
            //operations do NOT need a buffer, but receive/send operations do.
            //You can see that is true by looking at the
            //methods in the .NET Socket class on the Microsoft website.
            //ReceiveAsync and SendAsync take
            //a parameter for buffer size in SocketAsyncEventArgs.Buffer.

            //Preallocate pool of SocketAsyncEventArgs for receive/send operations.
            if (Program.watchProgramFlow == true)   //for testing
            {
                Program.testWriter.WriteLine("Creating receive/send SocketAsyncEventArgs pool");
            }

            SocketAsyncEventArgs eventArgObjectForPool;

            for (int i = 0; i < this.socketClientSettings.NumberOfSaeaForRecSend; i++)
            {
                //If you have different needs for the send versus the receive sockets, then
                //you might want to allocate a separate pool of SocketAsyncEventArgs for send
                //operations instead of having SocketAsyncEventArgs that do both receiving
                //and sending operations.

                //Allocate the SocketAsyncEventArgs object.
                eventArgObjectForPool = new SocketAsyncEventArgs();

                // assign a byte buffer from the buffer block to
                //this particular SocketAsyncEventArg object
                this.bufferManager.SetBuffer(eventArgObjectForPool);
                //Since we assigned a buffer like that, you can NOT just add more of
                //these send/receive SAEA objects if you run out of them.

                //Attach the receive/send-operation-SocketAsyncEventArgs object
                //to its event handler. Since this SocketAsyncEventArgs object is used
                //for both receive and send operations, whenever either of those
                //completes, the IO_Completed method will be called.
                eventArgObjectForPool.Completed += new EventHandler <SocketAsyncEventArgs>(IO_Completed);

                DataHoldingUserToken receiveSendToken = new DataHoldingUserToken(eventArgObjectForPool.Offset, eventArgObjectForPool.Offset + this.socketClientSettings.BufferSize, this.socketClientSettings.ReceivePrefixLength, this.socketClientSettings.SendPrefixLength, (this.poolOfRecSendEventArgs.AssignTokenId() + 1000000));

                //Create an object that we can write data to, and remove as an object
                //from the UserToken, if we wish.
                receiveSendToken.CreateNewDataHolder();

                eventArgObjectForPool.UserToken = receiveSendToken;
                // add this SocketAsyncEventArg object to the pool.
                this.poolOfRecSendEventArgs.Push(eventArgObjectForPool);
            }
            Console.WriteLine("Object pools built.");
        }