private void ProcessReceive(SocketAsyncEventArgs readEventArgs)
        {
            AsyncEventClient client = (AsyncEventClient)readEventArgs.UserToken;

            if (client == null)
            {
                Logger.Error($"{_identity}ProcessReceive - Client is null");
                return;
            }

            if (readEventArgs.BytesTransferred > 0 && readEventArgs.SocketError == SocketError.Success)
            {
                byte[] data = new byte[readEventArgs.BytesTransferred];
                Buffer.BlockCopy(readEventArgs.Buffer, readEventArgs.Offset, data, 0, readEventArgs.BytesTransferred);
                client.LastActive = DateTime.Now;
                try
                {
                    OnReceivedData(client, data);
                }
                catch (Exception ex)
                {
                    Logger.Error($"{_identity}Error during OnReceivedData() user code ({client.Identity})");
                    Logger.Exception(ex);
                }

                StartReceive(readEventArgs);
            }
            else
            {
                client.Close();
            }
        }
        private void StartReceive(SocketAsyncEventArgs readEventArgs)
        {
            AsyncEventClient client = (AsyncEventClient)readEventArgs.UserToken;

            if (client == null)
            {
                Logger.Error($"{_identity}StartReceive - Client is null");
                return;
            }

            bool willRaiseEvent;

            try
            {
                willRaiseEvent = client.Socket.ReceiveAsync(readEventArgs);
            }
            catch (ObjectDisposedException)
            {
                client.Close();
                return;
            }
            catch (InvalidOperationException)
            {
                Logger.Error($"{_identity}Error during StartReceive: InvalidOperationException ({client.Identity})");
                StartReceive(readEventArgs);
                return;
            }

            if (!willRaiseEvent)
            {
                ProcessReceive(readEventArgs);
            }
        }
        internal void NotifyDisconnected(AsyncEventClient client)
        {
            if (client.ReadEventArgs == null)
            {
                Logger.Error($"{_identity}Already returned AsyncEventArgs to poll ({client.Identity})");
                return;
            }

            FreeUnitOfOrder(client.UnitOfOrder);
            ReleaseAccept(client.ReadEventArgs);
            if (!_clients.Remove(client))
            {
                Logger.Error($"{_identity}Could not remove client from list. ({client.Identity})");
            }

            Logger.Debug($"{_identity}Free Receive: {_maxNumberAcceptedClients.CurrentCount}");
            Logger.Debug($"{_identity}Free Send: {_maxNumberSendOperations.CurrentCount}");
            Logger.Debug($"{_identity}NotifyDisconnected::Current Connections: {_clients.Count}");
            try
            {
                OnClientDisconnected(client);
            }
            catch (Exception ex)
            {
                Logger.Error($"{_identity}Error during OnClientDisconnected() user code ({client.Identity})");
                Logger.Exception(ex);
            }
        }
        private void ProcessAccept(SocketAsyncEventArgs acceptEventArg)
        {
            Socket      acceptSocket = acceptEventArg.AcceptSocket;
            SocketError socketError  = acceptEventArg.SocketError;

            acceptEventArg.AcceptSocket = null;
            _acceptPool.Push(acceptEventArg);
            _maxNumberAccepts.Release();
            StartAccept();

            if (socketError == SocketError.Success)
            {
                if (!_receivePool.TryPop(out SocketAsyncEventArgs readEventArgs))
                {
                    Logger.Error($"{_identity}Could not acquire readEventArgs");
                    _maxNumberAcceptedClients.Release();
                    return;
                }

                int unitOfOrder = ClaimUnitOfOrder();
                Logger.Debug($"{_identity}ProcessAccept::Claimed UnitOfOrder: {unitOfOrder}");
                AsyncEventClient client = new AsyncEventClient(
                    acceptSocket,
                    readEventArgs,
                    this,
                    unitOfOrder,
                    _settings.MaxSimultaneousSendsPerClient
                    );
                _clients.Add(client);
                readEventArgs.UserToken = client;
                Interlocked.Increment(ref _acceptedConnections);
                Logger.Debug($"{_identity}ProcessAccept::Current Connections: {_clients.Count}");
                Logger.Debug($"{_identity}Accepted Connections: {_acceptedConnections}");
                try
                {
                    OnClientConnected(client);
                }
                catch (Exception ex)
                {
                    Logger.Error($"{_identity}Error during OnClientConnected() user code ({client.Identity})");
                    Logger.Exception(ex);
                }

                StartReceive(readEventArgs);
            }
            else
            {
                if (socketError == SocketError.OperationAborted)
                {
                    Logger.Info($"{_identity}Accept Socket aborted");
                }
                else
                {
                    Logger.Error($"{_identity}Accept Socket Error: {socketError}");
                }

                _maxNumberAcceptedClients.Release();
            }
        }
        public void Send(AsyncEventClient client, byte[] data)
        {
            _maxNumberSendOperations.Wait();
            if (!_isRunning)
            {
                Logger.Debug($"{_identity}Server stopped, not sending anymore.");
                _maxNumberSendOperations.Release();
                return;
            }

            if (!client.IsAlive)
            {
                _maxNumberSendOperations.Release();
                return;
            }

            if (!client.Socket.Connected)
            {
                Logger.Error(
                    $"{_identity}AsyncEventClient not connected during send, closing socket. ({client.Identity})");
                client.Close();
                _maxNumberSendOperations.Release();
                return;
            }

            if (!_sendPool.TryPop(out SocketAsyncEventArgs writeEventArgs))
            {
                Logger.Error(
                    $"{_identity}Could not acquire writeEventArgs, closing socket. ({client.Identity})");
                client.Close();
                _maxNumberSendOperations.Release();
                return;
            }
            AsyncEventToken token = (AsyncEventToken)writeEventArgs.UserToken;

            token.Assign(client, data);
            client.WaitSend();
            StartSend(writeEventArgs);
        }