Beispiel #1
0
        //____________________________________________________________________________
        // 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);
            }
        }
Beispiel #2
0
        //____________________________________________________________________________
        // 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);
            }
        }
Beispiel #3
0
        //____________________________________________________________________________
        // 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);
            }
        }
Beispiel #4
0
 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);
 }
Beispiel #5
0
 internal SocketAsyncEventArgs GiveBack()
 {
     if (Program.watchProgramFlow == true)   //for testing
     {
         receiveSendToken = (DataHoldingUserToken)this.saeaObject.UserToken;
         Program.testWriter.WriteLine("Mediator GiveBack() " + receiveSendToken.TokenId);
     }
     return(saeaObject);
 }
Beispiel #6
0
 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);
 }
Beispiel #7
0
 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);
        }
Beispiel #9
0
        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);
        }
Beispiel #11
0
        //____________________________________________________________________________
        //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);
            }
        }
Beispiel #12
0
        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;
        }
Beispiel #13
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);
        }
Beispiel #14
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.

            // 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);
        }
Beispiel #15
0
 public ReceiveArgs(DataHoldingUserToken token)
 {
     this.Token = token;
 }
Beispiel #16
0
        //____________________________________________________________________________
        // 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);
            }
        }
Beispiel #17
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("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;
        }
Beispiel #18
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("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);
        }
Beispiel #19
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.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;
        }
Beispiel #20
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)
            { 
                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);
            }
        }