예제 #1
0
        /// <summary>
        /// Read data from socket into buffer and process.  Check if disposed after calling this, because
        /// this method will temporarily release the lock.
        /// </summary>
        private void ReceiveSocketData(SocketAsyncEventArgs args)
        {
            try {
                _syncLock.TakeRead();

                // exit if we're disposing
                if (_disposing)
                {
                    _syncLock.ReleaseRead();
                    return;
                }

                if (args.SocketError == SocketError.Success)
                {
                    // how many bytes did we receive?
                    int count = args.BytesTransferred;

                    if (count > 0)
                    {
                        // enqueue these bytes to read
                        _receivedBuffer.TakeItem().Enqueue(args.Buffer, 0, count);
                        _receivedBuffer.Release();

                        if (_readLock.TryTake)
                        {
                            ProcessReceivedData();
                        }
                    }

                    // deallocate the arguments
                    _syncLock.ReleaseRead();
                }
                else
                {
                    // deallocate the arguments
                    _syncLock.ReleaseRead();

                    if (_disposing)
                    {
                        return;
                    }
                    ProcessError("Socket Receive error '" + args.SocketError + "'.");
                }

                SocketEventArgsCache.DeallocateForReceive(args, OnSocketReceive);
            } catch (SocketException ex) {
                if (ex.SocketErrorCode == SocketError.ConnectionReset)
                {
                    SocketEventArgsCache.DeallocateForReceive(args, OnSocketReceive);
                    Log.Warning("Socket connection to '" + RemoteEndPoint + "' was reset.");
                }

                _syncLock.ReleaseRead();
                ProcessError(ex);
            } catch (Exception ex) {
                // we want to catch exceptions outside of the lock
                _syncLock.ReleaseRead();
                ProcessError(ex);
            }
        }
예제 #2
0
        /// <summary>
        /// Start receiving data from the socket.
        /// </summary>
        public void Start()
        {
            // don't start if disposing
            if (_disposing)
            {
                return;
            }

            // ensure we don't start multiple times
            if (Interlocked.CompareExchange(ref _started, 1, 0) == 1)
            {
                // already started! can't call Start() twice.
                throw new InvalidOperationException("Cannot call AsyncSocket.Start() more than once.");
            }

            // configure for receive
            var args = SocketEventArgsCache.AllocateForReceive(OnSocketReceive);

            // start a receive request and immediately check to see if the receive is already complete
            // otherwise OnIOCompleted will get called when the receive is complete
            if (!Socket.ReceiveAsync(args))
            {
                ReceiveSocketData(args);
            }
        }
예제 #3
0
        /// <summary>
        /// Creates a new AsyncSocket.  You must call Start() after creating the AsyncSocket
        /// in order to begin receive data.
        /// </summary>
        internal AsyncTcpSocket(Socket socket, IPEndPoint remoteEndpoint, IPEndPoint localEndpoint,
                                Action <byte[], int> onReceive, Action <Exception> onError)
        {
            Socket = socket;

            OnReceive = onReceive;
            OnError   = onError;

            RemoteEndPoint = remoteEndpoint;
            LocalEndPoint  = localEndpoint;

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

            _sendBuffer     = new Shared <BufferQueue>(new BufferQueue());
            _syncLock       = new LockReadWrite();
            _receivedBuffer = new Shared <BufferQueue>(new BufferQueue());
            _onReceive      = new ActionSequence();
            _callbacks      = new Queue <Teple <int, IAction> >();

            _sendSocketArgs = SocketEventArgsCache.AllocateForSend(OnSocketSend);
            _sendSocketArgs.SendPacketsFlags = TransmitFileOptions.UseKernelApc | TransmitFileOptions.UseSystemThread;
            _sendSocketArgs.RemoteEndPoint   = RemoteEndPoint;

            _disposing = false;
        }
예제 #4
0
        /// <summary>
        /// Complete processing a buffer of bytes read from the socket.
        /// </summary>
        private void CompleteReceive()
        {
            // ReadSocketData temporarily releases the lock (and then enters it again), so we need to ensure
            // we haven't disposed in the meantime
            if (_disposing)
            {
                _readLock.Release();
                return;
            }

            if (_receivedBuffer.TakeItem().Length > 0)
            {
                _receivedBuffer.Release();
                ManagerUpdate.Control.AddSingle(ProcessReceivedData);
                return;
            }
            _receivedBuffer.Release();

            // flop the processing flag
            _readLock.Release();

            // any bytes in the queue?
            if (_receivedBuffer.TakeItem().Length > 0 && _readLock.TryTake)
            {
                _receivedBuffer.Release();
                ManagerUpdate.Control.AddSingle(ProcessReceivedData);
                return;
            }
            _receivedBuffer.Release();

            // socket may have been closed already due to connection error.
            // if not try receiving more data
            if (Socket.Connected)
            {
                // receiveAsync returns true if the I/O operation is pending. An event will be raised upon completion.
                // returns false if the I/O operation completed synchronously.
                var args = SocketEventArgsCache.AllocateForReceive(OnSocketReceive);
                if (!Socket.ReceiveAsync(args))
                {
                    ReceiveSocketData(args);
                }
            }
            else
            {
                if (_disposing)
                {
                    return;
                }
                ProcessError("Cannot receive, socket is not connected.");
            }
        }
예제 #5
0
        /// <summary>
        /// Dispose this AsyncSocket. Closes the underlying socket if required.
        /// </summary>
        public void Dispose()
        {
            // ensure we haven't already disposed
            _syncLock.TakeWrite();
            if (_disposing)
            {
                _syncLock.ReleaseWrite();
                return;
            }
            _disposing = true;
            _syncLock.ReleaseWrite();

            // run sender dispose code
            if (_sendSocketArgs != null)
            {
                SocketEventArgsCache.DeallocateForSend(_sendSocketArgs, OnSocketSend);
                _sendSocketArgs = null;
            }
        }