Пример #1
0
        internal void GetDataToSend(SocketAsyncEventArgs e)
        {
            DataHoldingUserToken theUserToken = (DataHoldingUserToken)e.UserToken;
            DataHolder           dataHolder   = theUserToken.theDataHolder;

            //In this example code, we will
            //prefix the message with the length of the message. So we put 2
            //things into the array.
            // 1) prefix,
            // 2) the message.

            //Determine the length of the message that we will send.
            Int32 lengthOfCurrentOutgoingMessage = dataHolder.arrayOfMessagesToSend[dataHolder.NumberOfMessagesSent].Length;

            //convert the message to byte array
            Byte[] arrayOfBytesInMessage = Encoding.ASCII.GetBytes(dataHolder.arrayOfMessagesToSend[dataHolder.NumberOfMessagesSent]);

            //So, now we convert the length integer into a byte array.
            //Aren't byte arrays wonderful? Maybe you'll dream about byte arrays tonight!
            Byte[] arrayOfBytesInPrefix = BitConverter.GetBytes(lengthOfCurrentOutgoingMessage);

            //Create the byte array to send.
            theUserToken.dataToSend = new Byte[theUserToken.sendPrefixLength + lengthOfCurrentOutgoingMessage];

            //Now copy the 2 things to the theUserToken.dataToSend.
            Buffer.BlockCopy(arrayOfBytesInPrefix, 0, theUserToken.dataToSend, 0, theUserToken.sendPrefixLength);
            Buffer.BlockCopy(arrayOfBytesInMessage, 0, theUserToken.dataToSend, theUserToken.sendPrefixLength, lengthOfCurrentOutgoingMessage);

            theUserToken.sendBytesRemaining = theUserToken.sendPrefixLength + lengthOfCurrentOutgoingMessage;
            theUserToken.bytesSentAlready   = 0;
        }
        //____________________________________________________________________________
        private string ShowData(DataHoldingUserToken receiveSendToken)
        {
            Int32 count           = receiveSendToken.theDataHolder.listOfMessagesReceived.Count;
            Int32 lengthOfMessage = 0;

            StringBuilder sb = new StringBuilder();

            sb.Append("id ");
            sb.Append(receiveSendToken.TokenId);
            sb.Append(" received ");
            sb.Append(count);
            sb.Append(" messages:\r\n");
            for (int i = 0; i < count; i++)
            {
                lengthOfMessage = receiveSendToken.theDataHolder.listOfMessagesReceived[i].Length;
                //The server sent back its receivedTransmissionId value.
                //It is Int32, which is 4 bytes.
                Int32 transMissionIdOfServer = BitConverter.ToInt32(receiveSendToken.theDataHolder.listOfMessagesReceived[i], 0);
                sb.Append(transMissionIdOfServer.ToString());
                sb.Append(", ");
                sb.Append(Encoding.ASCII.GetString(receiveSendToken.theDataHolder.listOfMessagesReceived[i], 4, lengthOfMessage - 4));
                sb.Append("\r\n");
            }
            sb.Append("\r\n");
            return(sb.ToString());
        }
        //____________________________________________________________________________
        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();
            }
        }
        //____________________________________________________________________________
        // This method is called when an operation is completed on a socket
        //
        private void IO_Completed(object sender, SocketAsyncEventArgs e)
        {
            // determine which type of operation just completed and call the associated handler
            switch (e.LastOperation)
            {
            case SocketAsyncOperation.Connect:
                if (Program.watchProgramFlow == true)       //for testing
                {
                    ConnectOpUserToken theConnectingToken = (ConnectOpUserToken)e.UserToken;
                    Program.testWriter.WriteLine("\r\nIO_Completed method In Connect, connect id = " + theConnectingToken.TokenId);
                }

                ProcessConnect(e);
                break;

            case SocketAsyncOperation.Receive:
                if (Program.watchProgramFlow == true)       //for testing
                {
                    DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)e.UserToken;
                    Program.testWriter.WriteLine("\r\nIO_Completed method In Receive, id = " + receiveSendToken.TokenId);
                }

                ProcessReceive(e);
                break;

            case SocketAsyncOperation.Send:
                if (Program.watchProgramFlow == true)       //for testing
                {
                    DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)e.UserToken;
                    Program.testWriter.WriteLine("\r\nIO_Completed method In Send, id = " + receiveSendToken.TokenId);
                }

                ProcessSend(e);
                break;

            case SocketAsyncOperation.Disconnect:
                if (Program.watchProgramFlow == true)       //for testing
                {
                    DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)e.UserToken;
                    Program.testWriter.WriteLine("\r\nIO_Completed method In Disconnect, id = " + receiveSendToken.TokenId);
                }
                ProcessDisconnectAndCloseSocket(e);
                break;


            default:
            {
                DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)e.UserToken;
                if (Program.watchProgramFlow == true)           //for testing
                {
                    Program.testWriter.WriteLine("\r\nError in I/O Completed, id = " + receiveSendToken.TokenId);
                }

                throw new ArgumentException("\r\nError in I/O Completed, id = " + receiveSendToken.TokenId);
            }
            }
        }
        //____________________________________________________________________________
        private string AssembleMessage(DataHoldingUserToken receiveSendToken)
        {
            //The server sent back its receivedTransmissionId value and the message that we sent to it.
            //So the first 4 bytes represent an Int32.
            Int32  transMissionIdOfServer = BitConverter.ToInt32(receiveSendToken.theDataHolder.dataMessageReceived, 0);
            string messageString          = transMissionIdOfServer.ToString();
            string moreString             = Encoding.ASCII.GetString(receiveSendToken.theDataHolder.dataMessageReceived, 4, receiveSendToken.theDataHolder.dataMessageReceived.Length - 4);

            messageString = messageString + moreString;
            return(messageString);
        }
        //____________________________________________________________________________
        private void ProcessSend(SocketAsyncEventArgs receiveSendEventArgs)
        {
            DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken;

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

            if (receiveSendEventArgs.SocketError == SocketError.Success)
            {
                receiveSendToken.sendBytesRemaining = receiveSendToken.sendBytesRemaining - receiveSendEventArgs.BytesTransferred;
                // If this if statement is true, then we have sent all of the
                // bytes in the message. Otherwise, at least one more send
                // operation will be required to send the data.
                if (receiveSendToken.sendBytesRemaining == 0)
                {
                    //increment total number of messages sent in this test
                    Interlocked.Increment(ref this.totalCountOfMessagesSent);

                    //incrementing count of messages sent on this connection
                    receiveSendToken.theDataHolder.NumberOfMessagesSent++;
                    StartReceive(receiveSendEventArgs);
                }
                else
                {
                    // So since (receiveSendToken.sendBytesRemaining == 0) is false,
                    // we have more bytes to send for this message. So we need to
                    // call StartSend, so we can post another send message.
                    receiveSendToken.bytesSentAlready += receiveSendEventArgs.BytesTransferred;
                    StartSend(receiveSendEventArgs);
                }
            }
            else
            {
                //If we are in this else-statement, there was a socket error.
                if (Program.watchProgramFlow == true)   //for testing
                {
                    Program.testWriter.WriteLine("ProcessSend ERROR, id " + receiveSendToken.TokenId + "\r\n");
                }
                else if (Program.writeErrorsToLog == true)
                {
                    Program.testWriter.WriteLine("ProcessSend ERROR, id " + receiveSendToken.TokenId);
                }

                // We'll just close the socket if there was a
                // socket error when receiving data from the client.
                receiveSendToken.Reset();
                StartDisconnect(receiveSendEventArgs);
            }
        }
        //____________________________________________________________________________
        // Pass the connection info from the connecting object to the object
        // that will do send/receive. And put the connecting object back in the pool.
        //
        private void ProcessConnect(SocketAsyncEventArgs connectEventArgs)
        {
            ConnectOpUserToken theConnectingToken = (ConnectOpUserToken)connectEventArgs.UserToken;

            if (connectEventArgs.SocketError == SocketError.Success)
            {
                lock (this.lockerForConnectionCount)
                {
                    this.clientsNowConnectedCount++;
                    if (this.clientsNowConnectedCount > this.maxSimultaneousClientsThatWereConnected)
                    {
                        this.maxSimultaneousClientsThatWereConnected++;
                    }
                }

                SocketAsyncEventArgs receiveSendEventArgs = this.poolOfRecSendEventArgs.Pop();
                receiveSendEventArgs.AcceptSocket = connectEventArgs.AcceptSocket;

                //Earlier, in the UserToken of connectEventArgs we put an array
                //of messages to send. Now we move that array to the DataHolder in
                //the UserToken of receiveSendEventArgs.
                DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken;
                receiveSendToken.theDataHolder.PutMessagesToSend(theConnectingToken.outgoingMessageHolder.arrayOfMessages);

                if (Program.showConnectAndDisconnect == true)
                {
                    Program.testWriter.WriteLine("ProcessConnect connect id " + theConnectingToken.TokenId + " socket info now passing to\r\n   sendReceive id " + receiveSendToken.TokenId + ", local endpoint = " + IPAddress.Parse(((IPEndPoint)connectEventArgs.AcceptSocket.LocalEndPoint).Address.ToString()) + ": " + ((IPEndPoint)connectEventArgs.AcceptSocket.LocalEndPoint).Port.ToString() + ". Clients connected to server from this machine = " + this.clientsNowConnectedCount);
                }

                messagePreparer.GetDataToSend(receiveSendEventArgs);
                StartSend(receiveSendEventArgs);

                //release connectEventArgs object back to the pool.
                connectEventArgs.AcceptSocket = null;
                this.poolOfConnectEventArgs.Push(connectEventArgs);

                if (Program.watchProgramFlow == true)   //for testing
                {
                    Program.testWriter.WriteLine("back to pool for connection object " + theConnectingToken.TokenId);
                }
            }

            //This else statement is when there was a socket error
            else
            {
                ProcessConnectionError(connectEventArgs);
            }
        }
        //____________________________________________________________________________
        // Disconnect from the host.
        private void StartDisconnect(SocketAsyncEventArgs receiveSendEventArgs)
        {
            DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken;

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

            receiveSendEventArgs.AcceptSocket.Shutdown(SocketShutdown.Both);
            bool willRaiseEvent = receiveSendEventArgs.AcceptSocket.DisconnectAsync(receiveSendEventArgs);

            if (!willRaiseEvent)
            {
                ProcessDisconnectAndCloseSocket(receiveSendEventArgs);
            }
        }
        //____________________________________________________________________________
        //set the send buffer and post a send op
        private void StartSend(SocketAsyncEventArgs receiveSendEventArgs)
        {
            if (abortTest == true)
            {
                FinishTest();
                return;
            }

            DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken;

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

            if (receiveSendToken.sendBytesRemaining <= this.socketClientSettings.BufferSize)
            {
                receiveSendEventArgs.SetBuffer(receiveSendToken.bufferOffsetSend, receiveSendToken.sendBytesRemaining);
                //Copy the bytes to the buffer associated with this SAEA object.
                Buffer.BlockCopy(receiveSendToken.dataToSend, receiveSendToken.bytesSentAlready, receiveSendEventArgs.Buffer, receiveSendToken.bufferOffsetSend, receiveSendToken.sendBytesRemaining);
            }
            else
            {
                //We cannot try to set the buffer any larger than its size.
                //So since receiveSendToken.sendBytesRemaining > its size, we just
                //set it to the maximum size, to send the most data possible.
                receiveSendEventArgs.SetBuffer(receiveSendToken.bufferOffsetSend, this.socketClientSettings.BufferSize);
                //Copy the bytes to the buffer associated with this SAEA object.
                Buffer.BlockCopy(receiveSendToken.dataToSend, receiveSendToken.bytesSentAlready, receiveSendEventArgs.Buffer, receiveSendToken.bufferOffsetSend, this.socketClientSettings.BufferSize);

                //We'll change the value of sendUserToken.sendBytesRemaining
                //in the ProcessSend method.
            }

            //post the send
            bool willRaiseEvent = receiveSendEventArgs.AcceptSocket.SendAsync(receiveSendEventArgs);

            if (!willRaiseEvent)
            {
                Program.testWriter.WriteLine(" StartSend in if (!willRaiseEvent), id = " + receiveSendToken.TokenId);
                ProcessSend(receiveSendEventArgs);
            }
        }
        //____________________________________________________________________________
        // Set the receive buffer and post a receive op.
        private void StartReceive(SocketAsyncEventArgs receiveSendEventArgs)
        {
            DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken;

            //Set buffer for receive.
            receiveSendEventArgs.SetBuffer(receiveSendToken.bufferOffsetReceive, this.socketClientSettings.BufferSize);

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

            bool willRaiseEvent = receiveSendEventArgs.AcceptSocket.ReceiveAsync(receiveSendEventArgs);

            if (!willRaiseEvent)
            {
                Program.testWriter.WriteLine("StartReceive in if (!willRaiseEvent), id = " + receiveSendToken.TokenId);
                ProcessReceive(receiveSendEventArgs);
            }
        }
Пример #11
0
        public Int32 HandlePrefix(SocketAsyncEventArgs e, DataHoldingUserToken receiveSendToken, Int32 remainingBytesToProcess)
        {
            //receivedPrefixBytesDoneCount tells us how many prefix bytes were
            //processed during previous receive ops which contained data for
            //this message. Usually there will NOT have been any previous
            //receive ops here. So in that case,
            //receiveSendToken.receivedPrefixBytesDoneCount would equal 0.
            //Create a byte array to put the new prefix in, if we have not
            //already done it in a previous loop.
            if (receiveSendToken.receivedPrefixBytesDoneCount == 0)
            {
                if (Program.watchProgramFlow == true)   //for testing
                {
                    Program.testWriter.WriteLine("\r\nPrefixHandler, create prefix array " + receiveSendToken.TokenId);
                }
                receiveSendToken.byteArrayForPrefix = new Byte[receiveSendToken.receivePrefixLength];
            }

            //If this next if-statement is true, then we have received at
            //least enough bytes to have the prefix. So we can determine the
            //length of the message that we are working on.
            if (remainingBytesToProcess >= receiveSendToken.receivePrefixLength - receiveSendToken.receivedPrefixBytesDoneCount)
            {
                if (Program.watchProgramFlow == true)   //for testing
                {
                    Program.testWriter.WriteLine("\r\nPrefixHandler, enough for prefix " + receiveSendToken.TokenId + ". remainingBytesToProcess = " + remainingBytesToProcess);
                }
                //Now copy that many bytes to byteArrayForPrefix.
                //We can use the variable receiveMessageOffset as our main
                //index to show which index to get data from in the TCP
                //buffer.
                Buffer.BlockCopy(e.Buffer, receiveSendToken.receiveMessageOffset - receiveSendToken.receivePrefixLength + receiveSendToken.receivedPrefixBytesDoneCount, receiveSendToken.byteArrayForPrefix, receiveSendToken.receivedPrefixBytesDoneCount, receiveSendToken.receivePrefixLength - receiveSendToken.receivedPrefixBytesDoneCount);

                remainingBytesToProcess = remainingBytesToProcess - receiveSendToken.receivePrefixLength + receiveSendToken.receivedPrefixBytesDoneCount;

                receiveSendToken.recPrefixBytesDoneThisOp = receiveSendToken.receivePrefixLength - receiveSendToken.receivedPrefixBytesDoneCount;

                receiveSendToken.receivedPrefixBytesDoneCount = receiveSendToken.receivePrefixLength;

                receiveSendToken.lengthOfCurrentIncomingMessage = BitConverter.ToInt32(receiveSendToken.byteArrayForPrefix, 0);



                if (Program.watchData == true)
                {
                    //Now see what integer the prefix bytes represent, for the length.
                    StringBuilder sb = new StringBuilder(receiveSendToken.byteArrayForPrefix.Length);
                    sb.Append(" Token id " + receiveSendToken.TokenId + ". " + receiveSendToken.receivePrefixLength + " bytes in prefix:");
                    foreach (byte theByte in receiveSendToken.byteArrayForPrefix)
                    {
                        sb.Append(" " + theByte.ToString());
                    }
                    sb.Append(". Message length: " + receiveSendToken.lengthOfCurrentIncomingMessage);

                    Program.testWriter.WriteLine(sb.ToString());
                }
                return(remainingBytesToProcess);
            }

            //This next else-statement deals with the situation
            //where we have some bytes
            //of this prefix in this receive operation, but not all.
            else
            {
                if (Program.watchProgramFlow == true)   //for testing
                {
                    Program.testWriter.WriteLine("\r\nPrefixHandler, NOT all of prefix " + receiveSendToken.TokenId + ". remainingBytesToProcess = " + remainingBytesToProcess);
                }
                //Write the bytes to the array where we are putting the
                //prefix data, to save for the next loop.
                Buffer.BlockCopy(e.Buffer, receiveSendToken.receiveMessageOffset - receiveSendToken.receivePrefixLength + receiveSendToken.receivedPrefixBytesDoneCount, receiveSendToken.byteArrayForPrefix, receiveSendToken.receivedPrefixBytesDoneCount, remainingBytesToProcess);

                receiveSendToken.recPrefixBytesDoneThisOp      = remainingBytesToProcess;
                receiveSendToken.receivedPrefixBytesDoneCount += remainingBytesToProcess;
                remainingBytesToProcess = 0;
            }

            // Deal with the situation where we got exactly the amount of data
            // needed for the prefix, but no more.
            if (remainingBytesToProcess == 0)
            {
                receiveSendToken.receiveMessageOffset     = receiveSendToken.receiveMessageOffset - receiveSendToken.recPrefixBytesDoneThisOp;
                receiveSendToken.recPrefixBytesDoneThisOp = 0;
            }
            return(remainingBytesToProcess);
        }
Пример #12
0
        public bool HandleMessage(SocketAsyncEventArgs receiveSendEventArgs, DataHoldingUserToken receiveSendToken, Int32 remainingBytesToProcess)
        {
            bool incomingTcpMessageIsReady = false;

            //Create the array where we'll store the complete message,
            //if it has not been created on a previous receive op.
            if (receiveSendToken.receivedMessageBytesDoneCount == 0)
            {
                if (Program.watchProgramFlow == true)   //for testing
                {
                    Program.testWriter.WriteLine("\r\nMessageHandler, creating receive array " + receiveSendToken.TokenId);
                }
                receiveSendToken.theDataHolder.dataMessageReceived = new Byte[receiveSendToken.lengthOfCurrentIncomingMessage];
            }

            // Remember there is a receiveSendToken.receivedPrefixBytesDoneCount
            // variable, which allowed us to handle the prefix even when it
            // requires multiple receive ops. In the same way, we have a
            // receiveSendToken.receivedMessageBytesDoneCount variable, which
            // helps us handle message data, whether it requires one receive
            // operation or many.
            if (remainingBytesToProcess + receiveSendToken.receivedMessageBytesDoneCount == receiveSendToken.lengthOfCurrentIncomingMessage)
            {
                // If we are inside this if-statement, then we got
                // the end of the message. In other words,
                // the total number of bytes we received for this message matched the
                // message length value that we got from the prefix.

                if (Program.watchProgramFlow == true)   //for testing
                {
                    Program.testWriter.WriteLine("\r\nMessageHandler, length is right " + receiveSendToken.TokenId);
                }

                // Write/append the bytes received to the byte array in the
                // DataHolder object that we are using to store our data.
                Buffer.BlockCopy(receiveSendEventArgs.Buffer, receiveSendToken.receiveMessageOffset, receiveSendToken.theDataHolder.dataMessageReceived, receiveSendToken.receivedMessageBytesDoneCount, remainingBytesToProcess);

                incomingTcpMessageIsReady = true;
            }

            else
            {
                // If we are inside this else-statement, then that means that we
                // need another receive op. We still haven't got the whole message,
                // even though we have examined all the data that was received.
                // Not a problem. We just do another receive op to receive more data.

                if (Program.watchProgramFlow == true)   //for testing
                {
                    Program.testWriter.WriteLine("\r\nMessageHandler, length is short " + receiveSendToken.TokenId);
                }

                Buffer.BlockCopy(receiveSendEventArgs.Buffer, receiveSendToken.receiveMessageOffset, receiveSendToken.theDataHolder.dataMessageReceived, receiveSendToken.receivedMessageBytesDoneCount, remainingBytesToProcess);

                receiveSendToken.receiveMessageOffset = receiveSendToken.receiveMessageOffset - receiveSendToken.recPrefixBytesDoneThisOp;

                receiveSendToken.receivedMessageBytesDoneCount += remainingBytesToProcess;
            }

            return(incomingTcpMessageIsReady);
        }
        //____________________________________________________________________________
        // 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.");
        }
        //____________________________________________________________________________
        private void ProcessReceive(SocketAsyncEventArgs receiveSendEventArgs)
        {
            DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken;

            // If there was a socket error, close the connection.
            if (receiveSendEventArgs.SocketError != SocketError.Success)
            {
                if (Program.watchProgramFlow == true)   //for testing
                {
                    Program.testWriter.WriteLine("ProcessReceive ERROR " + receiveSendEventArgs.SocketError.ToString() + ", id " + receiveSendToken.TokenId);
                }
                else if (Program.writeErrorsToLog == true)
                {
                    Program.testWriter.WriteLine("ProcessReceive ERROR " + receiveSendEventArgs.SocketError.ToString() + ", id " + receiveSendToken.TokenId);
                }

                receiveSendToken.Reset();
                StartDisconnect(receiveSendEventArgs);
                return;
            }

            //If no data was received, close the connection.
            if (receiveSendEventArgs.BytesTransferred == 0)
            {
                if (Program.watchProgramFlow == true)   //for testing
                {
                    Program.testWriter.WriteLine("ProcessReceive NO DATA, id " + receiveSendToken.TokenId);
                }
                receiveSendToken.Reset();
                StartDisconnect(receiveSendEventArgs);
                return;
            }

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


            Int32 remainingBytesToProcess = receiveSendEventArgs.BytesTransferred;

            if (Program.watchProgramFlow == true)   //for testing
            {
                Program.testWriter.WriteLine("ProcessReceive() if Success, id " + receiveSendToken.TokenId + ". Bytes read this op = " + receiveSendEventArgs.BytesTransferred + ".");
            }
            if (Program.watchData == true)
            {
                //This only gives us a readable string if it is operating on
                //string data.
                string tempString = Encoding.ASCII.GetString(receiveSendEventArgs.Buffer, receiveSendToken.bufferOffsetReceive, receiveSendEventArgs.BytesTransferred);

                Program.testWriter.WriteLine(receiveSendToken.TokenId + " data received = " + tempString);
            }


            // If we have not got all of the prefix then we need to work on it.
            // receivedPrefixBytesDoneCount tells us how many prefix bytes were
            // processed during previous receive ops which contained data for
            // this message. (In normal use, usually there will NOT have been any
            // previous receive ops here. So receivedPrefixBytesDoneCount would be 0.)
            if (receiveSendToken.receivedPrefixBytesDoneCount < this.socketClientSettings.ReceivePrefixLength)
            {
                remainingBytesToProcess = prefixHandler.HandlePrefix(receiveSendEventArgs, receiveSendToken, remainingBytesToProcess);

                if (remainingBytesToProcess == 0)
                {
                    // We need to do another receive op, since we do not have
                    // the message yet.
                    StartReceive(receiveSendEventArgs);

                    //Jump out of the method, since there is no more data.
                    return;
                }
            }

            // If we have processed the prefix, we can work on the message now.
            // We'll arrive here when we have received enough bytes to read
            // the first byte after the prefix.
            bool incomingTcpMessageIsReady = messageHandler.HandleMessage(receiveSendEventArgs, receiveSendToken, remainingBytesToProcess);

            if (incomingTcpMessageIsReady == true)
            {
                //In the design of our SocketClient used for testing the
                //DataHolder can contain data for multiple messages. That is
                //different from the server design, where we have one DataHolder
                //for one message.

                if (Program.watchData == true)
                {
                    string messageString = AssembleMessage(receiveSendToken);
                    Program.testWriter.WriteLine("id " + receiveSendToken.TokenId + ", data = " + messageString);
                }

                //If we have set runLongTest to true, then we will assume that
                //we cannot put the data in memory, because there would be too much
                //data. So we'll just skip writing that data, in that case. We
                //write it when runLongTest == false.
                if (Program.runLongTest == false)
                {
                    //Write to DataHolder.
                    receiveSendToken.theDataHolder.listOfMessagesReceived.Add(receiveSendToken.theDataHolder.dataMessageReceived);
                }

                //null out the byte array, for the next message
                receiveSendToken.theDataHolder.dataMessageReceived = null;

                //Reset the variables in the UserToken, to be ready for the
                //next message that will be received on the socket in this
                //SAEA object.
                receiveSendToken.Reset();

                //If we have not sent all the messages, get the next message, and
                //loop back to StartSend.
                if (receiveSendToken.theDataHolder.NumberOfMessagesSent < this.socketClientSettings.NumberOfMessages)
                {
                    //No need to reset the buffer for send here.
                    //It is reset in the StartSend method.
                    messagePreparer.GetDataToSend(receiveSendEventArgs);
                    StartSend(receiveSendEventArgs);
                }
                else
                {
                    //Since we have sent all the messages that we planned to send,
                    //time to disconnect.
                    StartDisconnect(receiveSendEventArgs);
                }
            }
            else
            {
                // Since we have NOT gotten enough bytes for the whole message,
                // we need to do another receive op. Reset some variables first.

                // All of the data that we receive in the next receive op will be
                // message. None of it will be prefix. So, we need to move the
                // receiveSendToken.receiveMessageOffset to the beginning of the
                // buffer space for this SAEA.
                receiveSendToken.receiveMessageOffset = receiveSendToken.bufferOffsetReceive;

                // Do NOT reset receiveSendToken.receivedPrefixBytesDoneCount here.
                // Just reset recPrefixBytesDoneThisOp.
                receiveSendToken.recPrefixBytesDoneThisOp = 0;

                StartReceive(receiveSendEventArgs);
            }
        }