Esempio n. 1
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);
            }
        }
        //____________________________________________________________________________
        // 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);
            }
        }
Esempio n. 3
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);
            }
        }