예제 #1
0
        /// <summary>
        /// Creates a new AsyncSocket.  You must call Start() after creating the AsyncSocket
        /// in order to begin receive data.
        /// </summary>
        internal AsyncUdpSocket(Socket socket, IPEndPoint localEndpoint,
                                Action <IPEndPoint, byte[], int> onReceive, Action <Exception> onError)
        {
            Socket = socket;

            OnReceive = onReceive;
            OnError   = onError;

            LocalEndPoint  = localEndpoint;
            RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
            TargetEndPoint = RemoteEndPoint;

            _sendLock = new Lock();
            _readLock = new Lock();

            _enqueueBuffer = new BufferQueue();
            _sendQueue     = new Shared <ArrayRig <QueuedBuffer> >(new ArrayRig <QueuedBuffer>());

            _syncLock  = new LockReadWrite();
            _onReceive = new ActionSequence();

            _receiveBuffer  = BufferCache.Get();
            _receivedChunks = new Dictionary <int, ChunkedGram>();

            _disposing = false;
        }
예제 #2
0
        /// <summary>
        /// Start sending the enqueued bytes to the remote endpoint.
        /// </summary>
        public void Send(IAction onSent = null)
        {
            if (!_sendLock.TryTake)
            {
                _sendQueue.Take();

                _sendQueue.Item.Add(new QueuedBuffer {
                    EndPoint = TargetEndPoint,
                    Buffer   = _enqueueBuffer
                });
                _enqueueBuffer = null;

                _sendQueue.Release();

                return;
            }

            // ensure not disposing
            if (_disposing)
            {
                _sendLock.Release();
                return;
            }

            _onSent = onSent;

            SetSendBuffer(_enqueueBuffer, TargetEndPoint);
            _enqueueBuffer = null;

            try {
                // start sending the bytes in the buffer
                StartSend();
            } catch (SocketException ex) {
                _sendLock.Release();
                if (ex.SocketErrorCode == SocketError.ConnectionReset)
                {
                    return;
                }
                ProcessError(ex);
            } catch (Exception ex) {
                _sendLock.Release();
                // handle the error outside the lock
                ProcessError(ex);
            }
        }
예제 #3
0
        /// <summary>
        /// Set the buffer to be sent.
        /// </summary>
        private void SetSendBuffer(BufferQueue buffer, IPEndPoint endPoint)
        {
            _sendBuffer    = buffer;
            TargetEndPoint = endPoint;

            // should the buffer be chunked?
            if (_sendBuffer.Length > MaxDatagramSize)
            {
                // yes, set some of the chunked details
                _chunked    = true;
                _chunkIndex = 0;
                _chunkedId  = Randomize.Range(int.MinValue, int.MaxValue);
                _chunkCount = (int)Math.Ceiling((double)_sendBuffer.Length / (MaxDatagramSize - ChunkHeaderSize));
            }
            else
            {
                // no
                _chunked = false;
            }
        }
예제 #4
0
        /// <summary>
        /// Enqueue data to be sent to the remote host
        /// </summary>
        public void Enqueue(byte[] buffer, int index, int count)
        {
            // skip 0 bytes
            if (count == 0)
            {
                return;
            }

            // does the enqueue buffer need to be created? yes, create it
            if (_enqueueBuffer == null)
            {
                _sendQueue.Take();
                if (_enqueueBuffer == null)
                {
                    _enqueueBuffer = new BufferQueue();
                }
                _sendQueue.Release();
            }

            // enqueue bytes from the stream
            _enqueueBuffer.Enqueue(buffer, index, count);
        }
예제 #5
0
        /// <summary>
        /// Enqueue bytes from the specified stream to be sent.
        /// </summary>
        public void Enqueue(Stream stream, int length)
        {
            // skip 0 length
            if (length == 0)
            {
                return;
            }

            // does the enqueue buffer need to be created? yes, create it
            if (_enqueueBuffer == null)
            {
                _sendQueue.Take();
                if (_enqueueBuffer == null)
                {
                    _enqueueBuffer = new BufferQueue();
                }
                _sendQueue.Release();
            }

            // enqueue bytes from the stream
            _enqueueBuffer.Enqueue(stream, length);
        }
예제 #6
0
        /// <summary>
        /// Remove data that has been sent from the queue. Returns true if we should send more.
        /// Make sure slimLock is entered in read mode before calling this, and that disposing is not 1.
        /// Ensure an error handler is implemented which forwards to ProcessError.
        /// </summary>
        private bool CompleteSend(SocketAsyncEventArgs args)
        {
            // did it fail?
            if (args.SocketError != SocketError.Success)
            {
                _sendLock.Release();
                BufferCache.Set(args.Buffer);

                // it failed, let's invoke the error handler
                if (!_disposing)
                {
                    ProcessError("Socket error '" + args.SocketError + "'.");
                }

                args.Dispose();

                return(false);
            }

            BufferCache.Set(args.Buffer);
            args.Dispose();

            // is there a callback? yes, run it
            if (_onSent != null)
            {
                _onSent.Run();
            }

            // more data to send? yes, return positive
            if (_sendBuffer.Length > 0)
            {
                return(true);
            }

            // more buffers in queue?
            if (_sendQueue.TakeItem().Count > 0)
            {
                // yes, recycle send buffer if appropriate
                if (_enqueueBuffer == null)
                {
                    _enqueueBuffer = _sendBuffer;
                }

                // get the next buffer to send
                QueuedBuffer queuedBuffer = _sendQueue.Item.RemoveReturn(0);
                _sendQueue.Release();

                // set the send buffer
                SetSendBuffer(queuedBuffer.Buffer, queuedBuffer.EndPoint);

                return(true);
            }
            _sendQueue.Release();

            _sendLock.Release();

            // more data to send? yes, take the lock and return positive
            if (_sendBuffer.Length > 0 && _sendLock.TryTake)
            {
                return(true);
            }

            // more buffers in the queue? yes, take the lock and return positive
            if (_sendQueue.TakeItem().Count > 0 && _sendLock.TryTake)
            {
                // yes, recycle send buffer if appropriate
                if (_enqueueBuffer == null)
                {
                    _enqueueBuffer = _sendBuffer;
                }

                // get the next buffer to send
                QueuedBuffer queuedBuffer = _sendQueue.Item.RemoveReturn(0);
                _sendQueue.Release();

                // set the send buffer
                SetSendBuffer(queuedBuffer.Buffer, queuedBuffer.EndPoint);

                return(true);
            }
            _sendQueue.Release();

            return(false);
        }