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