//____________________________________________________________________________ // This method is called by I/O Completed() when an asynchronous send completes. // If all of the data has been sent, then this method calls StartReceive //to start another receive op on the socket to read any additional // data sent from the client. If all of the data has NOT been sent, then it //calls StartSend to send more data. private void ProcessSend(SocketAsyncEventArgs receiveSendEventArgs) { DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken; if (receiveSendEventArgs.SocketError == SocketError.Success) { receiveSendToken.sendBytesRemainingCount = receiveSendToken.sendBytesRemainingCount - receiveSendEventArgs.BytesTransferred; if (receiveSendToken.sendBytesRemainingCount == 0) { // If we are within this if-statement, then all the bytes in // the message have been sent. StartReceive(receiveSendEventArgs); } else { // If some of the bytes in the message have NOT been sent, // then we will need to post another send operation, after we store // a count of how many bytes that we sent in this send op. receiveSendToken.bytesSentAlreadyCount += receiveSendEventArgs.BytesTransferred; // So let's loop back to StartSend(). StartSend(receiveSendEventArgs); } } else { //If we are in this else-statement, there was a socket error. // We'll just close the socket if there was a // socket error when receiving data from the client. receiveSendToken.Reset(); CloseClientSocket(receiveSendEventArgs); } }
//____________________________________________________________________________ // Set the receive buffer and post a receive op. private void StartReceive(SocketAsyncEventArgs receiveSendEventArgs) { DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken; //Set the buffer for the receive operation. receiveSendEventArgs.SetBuffer(receiveSendToken.bufferOffsetReceive, this.socketListenerSettings.BufferSize); // Post async receive operation on the socket. bool willRaiseEvent = receiveSendEventArgs.AcceptSocket.ReceiveAsync(receiveSendEventArgs); //Socket.ReceiveAsync returns true if the I/O operation is pending. The //SocketAsyncEventArgs.Completed event on the e parameter will be raised //upon completion of the operation. So, true will cause the IO_Completed //method to be called when the receive operation completes. //That's because of the event handler we created when building //the pool of SocketAsyncEventArgs objects that perform receive/send. //It was the line that said //eventArgObjectForPool.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed); //Socket.ReceiveAsync returns false if I/O operation completed synchronously. //In that case, the SocketAsyncEventArgs.Completed event on the e parameter //will not be raised and the e object passed as a parameter may be //examined immediately after the method call //returns to retrieve the result of the operation. // It may be false in the case of a socket error. if (!willRaiseEvent) { //If the op completed synchronously, we need to call ProcessReceive //method directly. This will probably be used rarely, as you will //see in testing. ProcessReceive(receiveSendEventArgs); } }
//____________________________________________________________________________ // initializes the server by preallocating reusable buffers and // context objects (SocketAsyncEventArgs objects). //It is NOT mandatory that you preallocate them or reuse them. But, but it is //done this way to illustrate how the API can // easily be used to create reusable objects to increase server performance. internal void Init() { // Allocate one large byte buffer block, which all I/O operations will //use a piece of. This gaurds against memory fragmentation. this.theBufferManager.InitBuffer(); // preallocate pool of SocketAsyncEventArgs objects for accept operations for (Int32 i = 0; i < this.socketListenerSettings.MaxAcceptOps; i++) { // add SocketAsyncEventArg to the pool this.poolOfAcceptEventArgs.Push(CreateNewSaeaForAccept(poolOfAcceptEventArgs)); } //The pool that we built ABOVE is for SocketAsyncEventArgs objects that do // accept operations. //Now we will build a separate pool for SAEAs objects //that do receive/send operations. One reason to separate them is that accept //operations do NOT need a buffer, but receive/send operations do. //ReceiveAsync and SendAsync require //a parameter for buffer size in SocketAsyncEventArgs.Buffer. // So, create pool of SAEA objects for receive/send operations. SocketAsyncEventArgs eventArgObjectForPool; Int32 tokenId; for (Int32 i = 0; i < this.socketListenerSettings.NumberOfSaeaForRecSend; i++) { //Allocate the SocketAsyncEventArgs object for this loop, //to go in its place in the stack which will be the pool //for receive/send operation context objects. eventArgObjectForPool = new SocketAsyncEventArgs(); // assign a byte buffer from the buffer block to //this particular SocketAsyncEventArg object this.theBufferManager.SetBuffer(eventArgObjectForPool); tokenId = poolOfRecSendEventArgs.AssignTokenId() + 1000000; //Attach the 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); //We can store data in the UserToken property of SAEA object. DataHoldingUserToken theTempReceiveSendUserToken = new DataHoldingUserToken(eventArgObjectForPool, eventArgObjectForPool.Offset, eventArgObjectForPool.Offset + this.socketListenerSettings.BufferSize, this.socketListenerSettings.ReceivePrefixLength, this.socketListenerSettings.SendPrefixLength, tokenId); //We'll have an object that we call DataHolder, that we can remove from //the UserToken when we are finished with it. So, we can hang on to the //DataHolder, pass it to an app, serialize it, or whatever. theTempReceiveSendUserToken.CreateNewDataHolder(); eventArgObjectForPool.UserToken = theTempReceiveSendUserToken; // add this SocketAsyncEventArg object to the pool. this.poolOfRecSendEventArgs.Push(eventArgObjectForPool); } }
internal void HandleData(DataHolder incomingDataHolder) { if (Program.watchProgramFlow == true) //for testing { receiveSendToken = (DataHoldingUserToken)this.saeaObject.UserToken; Program.testWriter.WriteLine("Mediator HandleData() " + receiveSendToken.TokenId); } theDataHolder = theIncomingDataPreparer.HandleReceivedData(incomingDataHolder, this.saeaObject); }
internal SocketAsyncEventArgs GiveBack() { if (Program.watchProgramFlow == true) //for testing { receiveSendToken = (DataHoldingUserToken)this.saeaObject.UserToken; Program.testWriter.WriteLine("Mediator GiveBack() " + receiveSendToken.TokenId); } return(saeaObject); }
public void HandleData(DataHolder incomingDataHolder) { if (Program.watchProgramFlow == true) //for testing { receiveSendToken = (DataHoldingUserToken)this.saeaObject.UserToken; Program.testWriter.WriteLine("Mediator HandleData() " + receiveSendToken.TokenId); } theDataHolder = theIncomingDataPreparer.HandleReceivedData(incomingDataHolder, this.saeaObject); }
public SocketAsyncEventArgs GiveBack() { if (Program.watchProgramFlow == true) //for testing { receiveSendToken = (DataHoldingUserToken)this.saeaObject.UserToken; Program.testWriter.WriteLine("Mediator GiveBack() " + receiveSendToken.TokenId); } return saeaObject; }
internal void PrepareOutgoingData() { if (Program.watchProgramFlow == true) //for testing { receiveSendToken = (DataHoldingUserToken)this.saeaObject.UserToken; Program.testWriter.WriteLine("Mediator PrepareOutgoingData() " + receiveSendToken.TokenId); } theOutgoingDataPreparer.PrepareOutgoingData(saeaObject, theDataHolder); }
internal DataHolder HandleReceivedData(DataHolder incomingDataHolder, SocketAsyncEventArgs theSaeaObject) { DataHoldingUserToken receiveToken = (DataHoldingUserToken)theSaeaObject.UserToken; theDataHolder = incomingDataHolder; theDataHolder.sessionId = receiveToken.SessionId; theDataHolder.receivedTransMissionId = this.ReceivedTransMissionIdGetter(); theDataHolder.remoteEndpoint = this.GetRemoteEndpoint(); if ((Program.watchData == true) & (Program.runLongTest == false)) { this.AddDataHolder(); } return(theDataHolder); }
//____________________________________________________________________________ //Post a send. private void StartSend(SocketAsyncEventArgs receiveSendEventArgs) { DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken; //Set the buffer. You can see on Microsoft's page at //http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.setbuffer.aspx //that there are two overloads. One of the overloads has 3 parameters. //When setting the buffer, you need 3 parameters the first time you set it, //which we did in the Init method. The first of the three parameters //tells what byte array to use as the buffer. After we tell what byte array //to use we do not need to use the overload with 3 parameters any more. //(That is the whole reason for using the buffer block. You keep the same //byte array as buffer always, and keep it all in one block.) //Now we use the overload with two parameters. We tell // (1) the offset and // (2) the number of bytes to use, starting at the offset. //The number of bytes to send depends on whether the message is larger than //the buffer or not. If it is larger than the buffer, then we will have //to post more than one send operation. If it is less than or equal to the //size of the send buffer, then we can accomplish it in one send op. if (receiveSendToken.sendBytesRemainingCount <= this.socketListenerSettings.BufferSize) { receiveSendEventArgs.SetBuffer(receiveSendToken.bufferOffsetSend, receiveSendToken.sendBytesRemainingCount); //Copy the bytes to the buffer associated with this SAEA object. Buffer.BlockCopy(receiveSendToken.dataToSend, receiveSendToken.bytesSentAlreadyCount, receiveSendEventArgs.Buffer, receiveSendToken.bufferOffsetSend, receiveSendToken.sendBytesRemainingCount); } else { //We cannot try to set the buffer any larger than its size. //So since receiveSendToken.sendBytesRemainingCount > BufferSize, we just //set it to the maximum size, to send the most data possible. receiveSendEventArgs.SetBuffer(receiveSendToken.bufferOffsetSend, this.socketListenerSettings.BufferSize); //Copy the bytes to the buffer associated with this SAEA object. Buffer.BlockCopy(receiveSendToken.dataToSend, receiveSendToken.bytesSentAlreadyCount, receiveSendEventArgs.Buffer, receiveSendToken.bufferOffsetSend, this.socketListenerSettings.BufferSize); //We'll change the value of sendUserToken.sendBytesRemainingCount //in the ProcessSend method. } //post asynchronous send operation bool willRaiseEvent = receiveSendEventArgs.AcceptSocket.SendAsync(receiveSendEventArgs); if (!willRaiseEvent) { ProcessSend(receiveSendEventArgs); } }
internal void PrepareOutgoingData(SocketAsyncEventArgs e, DataHolder handledDataHolder) { DataHoldingUserToken theUserToken = (DataHoldingUserToken)e.UserToken; if (Program.watchProgramFlow == true) //for testing { Program.testWriter.WriteLine("Mediator PrepareOutgoingData() " + theUserToken.TokenId); } theDataHolder = handledDataHolder; //In this example code, we will send back the receivedTransMissionId, // followed by the //message that the client sent to the server. And we must //prefix it with the length of the message. So we put 3 //things into the array. // 1) prefix, // 2) receivedTransMissionId, // 3) the message that we received from the client, which // we stored in our DataHolder until we needed it. //That is our communication protocol. The client must know the protocol. //Convert the receivedTransMissionId to byte array. Byte[] idByteArray = BitConverter.GetBytes(theDataHolder.receivedTransMissionId); //Determine the length of all the data that we will send back. Int32 lengthOfCurrentOutgoingMessage = idByteArray.Length + theDataHolder.dataMessageReceived.Length; //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 3 things to the theUserToken.dataToSend. Buffer.BlockCopy(arrayOfBytesInPrefix, 0, theUserToken.dataToSend, 0, theUserToken.sendPrefixLength); Buffer.BlockCopy(idByteArray, 0, theUserToken.dataToSend, theUserToken.sendPrefixLength, idByteArray.Length); //The message that the client sent is already in a byte array, in DataHolder. Buffer.BlockCopy(theDataHolder.dataMessageReceived, 0, theUserToken.dataToSend, theUserToken.sendPrefixLength + idByteArray.Length, theDataHolder.dataMessageReceived.Length); theUserToken.sendBytesRemainingCount = theUserToken.sendPrefixLength + lengthOfCurrentOutgoingMessage; theUserToken.bytesSentAlreadyCount = 0; }
public void SendBufferSetter(SocketAsyncEventArgs e) { //Let's send back the receivedTransMissionId, followed by the //message that the client sent to the server. And we have to //prefix it with the length of the message. So we have to put 3 //things into the array. // 1) first prefix that tells the length // 2) then the receivedTransMissionId // 3) and last the message that we received from the client, which // we have stored in our trusty DataHolder until we needed it. //That is our data protocol. //Convert the receivedTransMissionId to byte array. Byte[] idByteArray = BitConverter.GetBytes(theDataHolder.receivedTransMissionId); //Determine the length of all the data that we will send back. Int32 lengthOfArrayToSend = Program.receivePrefixLength + idByteArray.Length + theDataHolder.dataMessageReceived.Length; //So, now we convert the integer which tells the length into a byte array. //Aren't byte arrays wonderful? Maybe you'll dream about byte arrays tonight Byte[] arrayOfBytesInPrefix = BitConverter.GetBytes(lengthOfArrayToSend - Program.receivePrefixLength); //Create the byte array to send. Byte[] arrayOfBytesToSend = new Byte[lengthOfArrayToSend]; //Now copy the 3 things to the arrayOfBytesToSend. Buffer.BlockCopy(arrayOfBytesInPrefix, 0, arrayOfBytesToSend, 0, Program.receivePrefixLength); Buffer.BlockCopy(idByteArray, 0, arrayOfBytesToSend, Program.receivePrefixLength, idByteArray.Length); //The message that the client sent is already in a byte array, in DataHolder. Buffer.BlockCopy(theDataHolder.dataMessageReceived, 0, arrayOfBytesToSend, Program.receivePrefixLength + idByteArray.Length, theDataHolder.dataMessageReceived.Length); // Great! Now tell SocketAsyncEventArgs object to send this byte array. //Your client will have to know the data protocol, in order to separate //the receivedTransMissionId from the message that we are echoing back, //because the message is ASCII but the receivedTransMissionId is binary. DataHoldingUserToken theUserToken = (DataHoldingUserToken)e.UserToken; Console.WriteLine("offset for send in DP = " + theUserToken.sendBufferOffset); Buffer.BlockCopy(arrayOfBytesToSend, 0, e.Buffer, theUserToken.sendBufferOffset, lengthOfArrayToSend); e.SetBuffer(e.Buffer, theUserToken.sendBufferOffset, lengthOfArrayToSend); }
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. // 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. // 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. In SocketListener.ProcessReceive we will just call // StartReceive to do another receive op to receive more data. Buffer.BlockCopy(receiveSendEventArgs.Buffer, receiveSendToken.receiveMessageOffset, receiveSendToken.theDataHolder.dataMessageReceived, receiveSendToken.receivedMessageBytesDoneCount, remainingBytesToProcess); receiveSendToken.receiveMessageOffset = receiveSendToken.receiveMessageOffset - receiveSendToken.recPrefixBytesDoneThisOp; receiveSendToken.receivedMessageBytesDoneCount += remainingBytesToProcess; } return(incomingTcpMessageIsReady); }
public ReceiveArgs(DataHoldingUserToken token) { this.Token = token; }
//____________________________________________________________________________ // This method is invoked by the IO_Completed method // when an asynchronous receive operation completes. // If the remote host closed the connection, then the socket is closed. // Otherwise, we process the received data. And if a complete message was // received, then we do some additional processing, to // respond to the client. private void ProcessReceive(SocketAsyncEventArgs receiveSendEventArgs) { DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken; // If there was a socket error, close the connection. This is NOT a normal // situation, if you get an error here. // In the Microsoft example code they had this error situation handled // at the end of ProcessReceive. Putting it here improves readability // by reducing nesting some. if (receiveSendEventArgs.SocketError != SocketError.Success) { receiveSendToken.Reset(); CloseClientSocket(receiveSendEventArgs); //Jump out of the ProcessReceive method. return; } // If no data was received, close the connection. This is a NORMAL // situation that shows when the client has finished sending data. if (receiveSendEventArgs.BytesTransferred == 0) { receiveSendToken.Reset(); CloseClientSocket(receiveSendEventArgs); return; } //The BytesTransferred property tells us how many bytes //we need to process. Int32 remainingBytesToProcess = receiveSendEventArgs.BytesTransferred; //If we have not got all of the prefix already, //then we need to work on it here. if (receiveSendToken.receivedPrefixBytesDoneCount < this.socketListenerSettings.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, but remainingBytesToProcess == 0. StartReceive(receiveSendEventArgs); //Jump out of the method. 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) { if (Program.watchData == true) { Program.testWriter.WriteLine(receiveSendToken.TokenId + ", Message in DataHolder = " + Encoding.ASCII.GetString(receiveSendToken.theDataHolder.dataMessageReceived) + "\r\n"); } //for testing only if (Program.msDelayAfterGettingMessage > -1) { //A Thread.Sleep here can be used to simulate delaying the //return of the SocketAsyncEventArgs object for receive/send //to the pool. Simulates doing some work here. if (Program.watchData == true) { Program.testWriter.WriteLine(receiveSendToken.TokenId + " waiting after read.\r\n"); } Thread.Sleep(Program.msDelayAfterGettingMessage); } // Pass the DataHolder object to the Mediator here. The data in // this DataHolder can be used for all kinds of things that an // intelligent and creative person like you might think of. receiveSendToken.theMediator.HandleData(receiveSendToken.theDataHolder); // Create a new DataHolder for next message. receiveSendToken.CreateNewDataHolder(); //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(); receiveSendToken.theMediator.PrepareOutgoingData(); StartSend(receiveSendToken.theMediator.GiveBack()); } 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 // receive buffer space for this SAEA. receiveSendToken.receiveMessageOffset = receiveSendToken.bufferOffsetReceive; // Do NOT reset receiveSendToken.receivedPrefixBytesDoneCount here. // Just reset recPrefixBytesDoneThisOp. receiveSendToken.recPrefixBytesDoneThisOp = 0; StartReceive(receiveSendEventArgs); } }
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("MessageHandler, creating receive array " + receiveSendToken.TokenId); } receiveSendToken.theDataHolder.dataMessageReceived = new Byte[receiveSendToken.lengthOfCurrentIncomingMessage]; Log.Info("HandleMessage:创建BUFFER:dataMessageReceived完成数据长度为:" + 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("MessageHandler, length is right for " + 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); Log.Info("HandleMessage:incomingTcpMessageIsReady 完成"); 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. In SocketListener.ProcessReceive we will just call // StartReceive to do another receive op to receive more data. if (Program.watchProgramFlow == true) //for testing { Program.testWriter.WriteLine(" MessageHandler, length is short for " + receiveSendToken.TokenId); } Buffer.BlockCopy(receiveSendEventArgs.Buffer, receiveSendToken.receiveMessageOffset, receiveSendToken.theDataHolder.dataMessageReceived, receiveSendToken.receivedMessageBytesDoneCount, remainingBytesToProcess); receiveSendToken.receiveMessageOffset = receiveSendToken.receiveMessageOffset - receiveSendToken.recPrefixBytesDoneThisOp; receiveSendToken.receivedMessageBytesDoneCount += remainingBytesToProcess; Log.Info("HandleMessage:持续接收中: receiveSendToken.receivedMessageBytesDoneCount=" + receiveSendToken.receivedMessageBytesDoneCount); } return incomingTcpMessageIsReady; }
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("PrefixHandler, create prefix array " + receiveSendToken.TokenId); } receiveSendToken.byteArrayForPrefix = new Byte[receiveSendToken.receivePrefixLength]; } // If this next if-statement is true, then we have received >= // 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("PrefixHandler, 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()); } } //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("PrefixHandler, 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; } // This section is needed when we have received // an amount of data exactly equal to the amount needed for the prefix, // but no more. And also needed with the situation where we have received // less than the amount of data needed for prefix. if (remainingBytesToProcess == 0) { receiveSendToken.receiveMessageOffset = receiveSendToken.receiveMessageOffset - receiveSendToken.recPrefixBytesDoneThisOp; receiveSendToken.recPrefixBytesDoneThisOp = 0; } return(remainingBytesToProcess); }
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.Log("PrefixHandler, create prefix array " + receiveSendToken.TokenId); } receiveSendToken.byteArrayForPrefix = new Byte[receiveSendToken.receivePrefixLength]; } // If this next if-statement is true, then we have received >= // 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.Log("PrefixHandler, 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. var 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.Log(sb.ToString()); } } //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.Log("PrefixHandler, 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; } // This section is needed when we have received // an amount of data exactly equal to the amount needed for the prefix, // but no more. And also needed with the situation where we have received // less than the amount of data needed for prefix. if (remainingBytesToProcess == 0) { receiveSendToken.receiveMessageOffset = receiveSendToken.receiveMessageOffset - receiveSendToken.recPrefixBytesDoneThisOp; receiveSendToken.recPrefixBytesDoneThisOp = 0; } return remainingBytesToProcess; }
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) { receiveSendToken.byteArrayForPrefix = new Byte[receiveSendToken.receivePrefixLength]; } // If this next if-statement is true, then we have received >= // 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) { //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); } //This next else-statement deals with the situation //where we have some bytes //of this prefix in this receive operation, but not all. else { //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; } // This section is needed when we have received // an amount of data exactly equal to the amount needed for the prefix, // but no more. And also needed with the situation where we have received // less than the amount of data needed for prefix. if (remainingBytesToProcess == 0) { receiveSendToken.receiveMessageOffset = receiveSendToken.receiveMessageOffset - receiveSendToken.recPrefixBytesDoneThisOp; receiveSendToken.recPrefixBytesDoneThisOp = 0; } return remainingBytesToProcess; }
//____________________________________________________________________________ //Display thread info. //Note that there is NOT a 1:1 ratio between managed threads //and system (native) threads. // //Overloaded. //Use this one after the DataHoldingUserToken is available. // private void DealWithThreadsForTesting(string methodName, DataHoldingUserToken receiveSendToken) { StringBuilder sb = new StringBuilder(); sb.Append(" In " + methodName + ", receiveSendToken id " + receiveSendToken.TokenId + ". Thread id " + Thread.CurrentThread.ManagedThreadId + ". Socket handle " + receiveSendToken.socketHandleNumber + "."); sb.Append(DealWithNewThreads()); Program.testWriter.WriteLine(sb.ToString()); }
//____________________________________________________________________________ // initializes the server by preallocating reusable buffers and // context objects (SocketAsyncEventArgs objects). //It is NOT mandatory that you preallocate them or reuse them. But, but it is //done this way to illustrate how the API can // easily be used to create reusable objects to increase server performance. internal void Init() { if (Program.watchProgramFlow == true) //for testing { Program.testWriter.WriteLine("Init method"); } if (Program.watchThreads == true) //for testing { DealWithThreadsForTesting("Init()"); } // Allocate one large byte buffer block, which all I/O operations will //use a piece of. This gaurds against memory fragmentation. this.theBufferManager.InitBuffer(); if (Program.watchProgramFlow == true) //for testing { Program.testWriter.WriteLine("Starting creation of accept SocketAsyncEventArgs pool:"); } // preallocate pool of SocketAsyncEventArgs objects for accept operations for (Int32 i = 0; i < this.socketListenerSettings.MaxAcceptOps; i++) { // add SocketAsyncEventArg to the pool this.poolOfAcceptEventArgs.Push(CreateNewSaeaForAccept(poolOfAcceptEventArgs)); } //The pool that we built ABOVE is for SocketAsyncEventArgs objects that do // accept operations. //Now we will build a separate pool for SAEAs objects //that do receive/send operations. One reason to separate them is that accept //operations do NOT need a buffer, but receive/send operations do. //ReceiveAsync and SendAsync require //a parameter for buffer size in SocketAsyncEventArgs.Buffer. // So, create pool of SAEA objects for receive/send operations. SocketAsyncEventArgs eventArgObjectForPool; if (Program.watchProgramFlow == true) //for testing { Program.testWriter.WriteLine("Starting creation of receive/send SocketAsyncEventArgs pool"); } Int32 tokenId; for (Int32 i = 0; i < this.socketListenerSettings.NumberOfSaeaForRecSend; i++) { //Allocate the SocketAsyncEventArgs object for this loop, //to go in its place in the stack which will be the pool //for receive/send operation context objects. eventArgObjectForPool = new SocketAsyncEventArgs(); // assign a byte buffer from the buffer block to //this particular SocketAsyncEventArg object this.theBufferManager.SetBuffer(eventArgObjectForPool); tokenId = poolOfRecSendEventArgs.AssignTokenId() + 1000000; //Attach the 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); //We can store data in the UserToken property of SAEA object. DataHoldingUserToken theTempReceiveSendUserToken = new DataHoldingUserToken(eventArgObjectForPool, eventArgObjectForPool.Offset, eventArgObjectForPool.Offset + this.socketListenerSettings.BufferSize, this.socketListenerSettings.ReceivePrefixLength, this.socketListenerSettings.SendPrefixLength, tokenId); //We'll have an object that we call DataHolder, that we can remove from //the UserToken when we are finished with it. So, we can hang on to the //DataHolder, pass it to an app, serialize it, or whatever. theTempReceiveSendUserToken.CreateNewDataHolder(); eventArgObjectForPool.UserToken = theTempReceiveSendUserToken; // add this SocketAsyncEventArg object to the pool. this.poolOfRecSendEventArgs.Push(eventArgObjectForPool); } }