Пример #1
0
        /// <summary>
        /// Called when a message has been successfully sent.
        ///
        /// Decodes the unsent bytes and tries sending them again.
        /// </summary>
        private void MessageSent(IAsyncResult result)
        {
            // Protect SendQueue
            lock (SendQueue)
            {
                try
                {
                    // Find out how many bytes were actually sent
                    int bytes = socket.EndSend(result);

                    // Get the bytes that we attempted to send
                    byte[] outgoingBuffer = (byte[])result.AsyncState;

                    // If no bytes were received, close the socket.
                    //if (bytes == 0)
                    //{
                    //    //what to do here???
                    //    socket.Close();
                    //}

                    // Prepend the unsent bytes and try sending again.
                    //else
                    {
                        outgoing = encoding.GetString(outgoingBuffer, bytes,
                                                      outgoingBuffer.Length - bytes) + outgoing;
                        SendBytes();
                    }
                }
                catch (Exception e)
                {
                    SendRequest sr2 = SendQueue.Dequeue();
                    ThreadPool.QueueUserWorkItem(x => sr2.sendCallback(e, sr2.payload));
                }
            }
        }
Пример #2
0
        /// <summary>
        /// We can write a string to a StringSocket ss by doing
        ///
        ///    ss.BeginSend("Hello world", callback, payload);
        ///
        /// where callback is a SendCallback (see below) and payload is an arbitrary object.
        /// This is a non-blocking, asynchronous operation.  When the StringSocket has
        /// successfully written the string to the underlying Socket, or failed in the
        /// attempt, it invokes the callback.  The parameters to the callback are a
        /// (possibly null) Exception and the payload.  If the Exception is non-null, it is
        /// the Exception that caused the send attempt to fail.
        ///
        /// This method is non-blocking.  This means that it does not wait until the string
        /// has been sent before returning.  Instead, it arranges for the string to be sent
        /// and then returns.  When the send is completed (at some time in the future), the
        /// callback is called on another thread.
        ///
        /// This method is thread safe.  This means that multiple threads can call BeginSend
        /// on a shared socket without worrying around synchronization.  The implementation of
        /// BeginSend must take care of synchronization instead.  On a given StringSocket, each
        /// string arriving via a BeginSend method call must be sent (in its entirety) before
        /// a later arriving string can be sent.
        /// </summary>
        public void BeginSend(String s, SendCallback callback, object payload)
        {
            SendRequest sendRequest = new SendRequest(s, callback, payload);

            SendQueue.Enqueue(sendRequest);

            SendMessage(SendQueue.Peek());
            SendRequest currnetSR = SendQueue.Dequeue();

            lock (sendSync)
            {
                ThreadPool.QueueUserWorkItem(x => currnetSR.sendCallBack(null, currnetSR.payload));
            }
        }
Пример #3
0
        /// <summary>
        /// Checks if the entire message has been sent. If the message hasn't been sent
        /// or there is another request, begin sending it.
        /// </summary>
        private void SendBytes()
        {
            if (SendQueue.Count > 0)
            {
                // If the entire message has been sent.
                if (outgoing == "")
                {
                    // Dequeue the send request.
                    SendRequest sr = SendQueue.Dequeue();

                    // Call the appropriate callback.
                    ThreadPool.QueueUserWorkItem(x => sr.sendCallback(null, sr.payload));

                    // If there's another request in the queue, get its message and begin sending it.
                    if (SendQueue.Count > 0)
                    {
                        outgoing = SendQueue.Peek().message;

                        byte[] outgoingBuffer = encoding.GetBytes(outgoing);
                        outgoing = "";
                        try
                        {
                            socket.BeginSend(outgoingBuffer, 0, outgoingBuffer.Length,
                                             SocketFlags.None, MessageSent, outgoingBuffer);
                        }
                        catch (Exception e)
                        {
                            SendRequest sr1 = SendQueue.Dequeue();
                            ThreadPool.QueueUserWorkItem(x => sr1.sendCallback(e, sr1.payload));
                        }
                    }
                }
                // Otherwise, the entire message has not been sent. Send more.
                else
                {
                    byte[] outgoingBuffer = encoding.GetBytes(outgoing);
                    outgoing = "";
                    try
                    {
                        socket.BeginSend(outgoingBuffer, 0, outgoingBuffer.Length,
                                         SocketFlags.None, MessageSent, outgoingBuffer);
                    }
                    catch (Exception e)
                    {
                        SendRequest sr2 = SendQueue.Dequeue();
                        ThreadPool.QueueUserWorkItem(x => sr2.sendCallback(e, sr2.payload));
                    }
                }
            }
        }
Пример #4
0
 /// <summary>
 /// This should be called only after a lock on sendRequests has been acquired.
 /// It pings back and forth with the BytesSent callback to send out all the strings in
 /// the queue.  This method gets the string at the front of the queue and attempts
 /// to send it.  BytesSent takes care of making sure all of the bytes are actually sent
 /// before calling this method again to send the next string.
 /// </summary>
 private void ProcessSendQueue()
 {
     while (sendRequests.Count > 0)
     {
         sendBytes = encoding.GetBytes(sendRequests.First().Text);
         try
         {
             socket.BeginSend(sendBytes, sendCount = 0, sendBytes.Length, SocketFlags.None, BytesSent, null);
             break;
         }
         catch (Exception e)
         {
             SendRequest req = sendRequests.Dequeue();
             ThreadPool.QueueUserWorkItem(x => req.Callback(e, req.Payload));
         }
     }
 }
Пример #5
0
        /// <summary>
        /// Sends a string to the client
        /// </summary>
        private void SendMessage(SendRequest sr)
        {
            // Get exclusive access to send mechanism
            lock (sendSync)
            {
                String message = sr.message;
                // Append the message to the unsent string
                outgoing += message;

                // If there's not a send ongoing, start one.
                if (!sendIsOngoing)
                {
                    sendIsOngoing = true;
                    SendBytes();
                }
            }
        }
Пример #6
0
 /// <summary>
 /// This helper method sends out all the strings in the queue by calling
 /// the BytesSent callback again and again. It tries to send the string at the
 /// front of queue. It contains a call to another helper method BytesSent
 /// to ensure all the bytes from the front string are sent before calling this
 /// method again to send the next string.
 ///
 /// IMPLEMENTATION NOTE: Should be called from within a lock for thread-safety.
 /// </summary>
 private void HandleSendQueue()
 {
     while (sendQueue.Count > 0)
     {
         sendBytes = encoding.GetBytes(sendQueue.First <SendRequest>().Text);
         try
         {
             socket.BeginSend(sendBytes, sendCount = 0, sendBytes.Length,
                              SocketFlags.None, new AsyncCallback(BytesSent), (object)null);
             break;
         }
         catch (Exception ex)
         {
             SendRequest request = sendQueue.Dequeue();
             ThreadPool.QueueUserWorkItem((WaitCallback)(x => request.SendBack(ex, request.Payload)));
         }
     }
 }
Пример #7
0
        /// <summary>
        /// This method is the callback used when bytes are being sent.  It makes sure that all of
        /// the bytes have been sent, then calls the appropriate callback and calls ProcessSendQueue.
        /// </summary>
        private void BytesSent(IAsyncResult ar)
        {
            try
            {
                // Compute how many bytes have been sent so far
                sendCount += socket.EndSend(ar);
            }
            catch (Exception e)
            {
                SendRequest req = sendRequests.Dequeue();
                ThreadPool.QueueUserWorkItem(x => req.Callback(e, req.Payload));
                ProcessSendQueue();
                return;
            }

            // If all the bytes were sent, remove the request from the queue, notify the
            // callback, and process the next entry in the send queue.
            if (sendCount == sendBytes.Length)
            {
                lock (sendRequests)
                {
                    SendRequest req = sendRequests.Dequeue();
                    ThreadPool.QueueUserWorkItem(x => req.Callback(null, req.Payload));
                    ProcessSendQueue();
                }
            }

            // If all the bytes weren't sent, send the rest.
            else
            {
                try
                {
                    socket.BeginSend(sendBytes, sendCount, sendBytes.Length - sendCount, SocketFlags.None, BytesSent, null);
                }

                catch (Exception e)
                {
                    SendRequest req = sendRequests.Dequeue();
                    ThreadPool.QueueUserWorkItem(x => req.Callback(e, req.Payload));
                    ProcessSendQueue();
                }
            }
        }
Пример #8
0
        /// <summary>
        /// We can write a string to a StringSocket ss by doing
        ///
        ///    ss.BeginSend("Hello world", callback, payload);
        ///
        /// where callback is a SendCallback (see below) and payload is an arbitrary object.
        /// This is a non-blocking, asynchronous operation.  When the StringSocket has
        /// successfully written the string to the underlying Socket, or failed in the
        /// attempt, it invokes the callback.  The parameters to the callback are a
        /// (possibly null) Exception and the payload.  If the Exception is non-null, it is
        /// the Exception that caused the send attempt to fail.
        ///
        /// This method is non-blocking.  This means that it does not wait until the string
        /// has been sent before returning.  Instead, it arranges for the string to be sent
        /// and then returns.  When the send is completed (at some time in the future), the
        /// callback is called on another thread.
        ///
        /// This method is thread safe.  This means that multiple threads can call BeginSend
        /// on a shared socket without worrying around synchronization.  The implementation of
        /// BeginSend must take care of synchronization instead.  On a given StringSocket, each
        /// string arriving via a BeginSend method call must be sent (in its entirety) before
        /// a later arriving string can be sent.
        /// </summary>
        public void BeginSend(String s, SendCallback callback, object payload)
        {
            // Protect SendQueue
            lock (SendQueue)
            {
                // Create and store the send request.
                SendRequest sendRequest = new SendRequest(s, callback, payload);
                SendQueue.Enqueue(sendRequest);

                // If there's not a send ongoing, start one.
                if (SendQueue.Count() == 1)
                {
                    // Append the message to the unsent string
                    outgoing += s;

                    SendBytes();
                }
            }
        }
Пример #9
0
        /// <summary>
        /// The callback method used when sending bytes. It makes sure that all of the bytes
        /// are sent before making the approriate callback and call to HandleSendQueue.
        ///
        /// IMPLEMENTATION NOTE: Should be called from within a lock for thread-safety.
        /// </summary>
        /// <param name="arg">Object containing status of asyn operation</param>
        private void BytesSent(IAsyncResult arg)
        {
            try
            {
                sendCount = sendCount + socket.EndSend(arg);
            }
            catch (Exception ex)
            {
                SendRequest request = sendQueue.Dequeue();
                ThreadPool.QueueUserWorkItem((WaitCallback)(x => request.SendBack(ex, request.Payload)));
                HandleSendQueue();
                return;
            }

            if (sendCount == sendBytes.Length)
            {
                lock (sendQueue)
                {
                    SendRequest req = sendQueue.Dequeue();
                    ThreadPool.QueueUserWorkItem((WaitCallback)(x => req.SendBack((Exception)null, req.Payload)));
                    HandleSendQueue();
                }
            }
            else
            {
                try
                {
                    socket.BeginSend(sendBytes, sendCount, sendBytes.Length - sendCount,
                                     SocketFlags.None, new AsyncCallback(BytesSent), (object)null);
                }
                catch (Exception ex)
                {
                    SendRequest request = sendQueue.Dequeue();
                    ThreadPool.QueueUserWorkItem((WaitCallback)(x => request.SendBack(ex, request.Payload)));
                    HandleSendQueue();
                }
            }
        }