Beispiel #1
0
        /// <summary>
        /// Initailizes the server by preallocating reusable buffers and
        /// context objects (SocketAsyncEventArgs objects).
        /// It is NOT mandatory that you preallocate them or reuse them. But, it is
        /// done this way to illustrate how the API can easily be used
        /// to create reusable objects to increase server performance.
        /// </summary>
        internal void Init()
        {
            // Allocate one large byte buffer block, which all I/O operations will
            // use a piece of. This guards against memory fragmentation.
            this.theBufferManager.InitBuffer();

            // Preallocate pool of SocketAsyncEventArgs objects for accept operations
            for (Int32 i = 0; i < this.socketListenerSettings.MaxAcceptOps; i++)
            {
                // Add SocketAsyncEventArgs 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 SocketAsyncEvnetArgs.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 n 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 pool.
                this.poolOfRecSendEventArgs.Push(eventArgObjectForPool);
            }
        }
Beispiel #2
0
        /// <summary>
        /// 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.
        /// </summary>
        /// <param name="receiveSendEventArgs"></param>
        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)
            {
                // 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;

                // Since we have not gotten enough bytes for the whole message,
                // we need to do another receive op.
                StartReceive(receiveSendEventArgs);
            }
        }