如何在等待用户响应的同时对事件处理程序中的传入事件进行排队

时间:2016-03-09 08:27:28

标签: c# .net events design-patterns

我使用的是C#,.NET Framework 4.5,VS2015。

我实现了一个由黑盒子模块触发的事件(TcpRequest)的事件处理程序。 我的事件处理程序调用一个私有方法,该方法将事件触发到客户端/ GUI并等待用户的响应。 同时黑盒子模块继续触发TcpRequest事件。不知何故,我需要在等待时排队传入的事件。 一旦用户给出第一个事件的响应,队列就可以被刷新"。

这种情况是否有任何设计模式或最佳做法(在等待用户的响应时排队)?我是否需要使用等待或其他什么?

以下是我的代码。请随时修改它们。提前谢谢。

public void TcpRequestHandler(int id, CONN_INFO connInfo)
{
    if (SomeCondition)
    {
        var myArgs = new MyEventArgs()
        {
            Id = id,
            ConnInfo = connInfo
        }

        // this the way I tried and I know it is wrong,
        // because it always fires event without "waiting in queue"
        lock (_eventQueue)
        {
            _eventQueue.Add(myArgs);
        }
        FireEventToClient(myArgs);
    }
}

private void FireEventToClient(MyEventArgs myArgs)
{
    EventToClient(this, myArgs);
    if (myArgs.Continue)
    {
        // "flush" the event queue
        ...
        // do other things
        ...
    }
}

public class MyEventArgs : EventArgs
{
    public int Id {get; private set;}
    public CONN_INFO ConnInfo {get; private set;}
    public bool Continue {get; set;} 
}

2 个答案:

答案 0 :(得分:0)

使用返回值声明您的事件 EventToClient 并使用返回的值进行验证并刷新事件队列

答案 1 :(得分:0)

检查一下,这可能有帮助

公共类TCPServer     {         private int _port;         private TcpListener _tcpListener;         private bool _running,_disposed;         private BinaryFormatter _bFormatter;         private Thread _connectionThread;         private BackgroundWorker _bgwListener;         私人BackgroundWorker _bgwSender;         私有对象syncobject = new object();         私有对象syncsendmessageobject = new object();

    /// <summary>
    /// Constructor - Initialises the TCPServer with the given port and a tcplistener. Starts a thread to monitor the message queue
    /// </summary>
    /// <param name="port"></param>
    public TCPServer(int port)
    {
        try
        {
            this._port = port;
            this._tcpListener = new TcpListener(IPAddress.Loopback, port);
            this._running = false;
            this._bFormatter = new BinaryFormatter();
            Thread thread = new Thread(ReadQueue);
            thread.Start();
        }
        catch (Exception ex)
        {
        }
    }

    /// <summary>
    /// Starts the tcplistener.
    /// </summary>
    public void Start()
    {
        try
        {
            if (!_running)
            {
                this.MessageReceived -= TCPServer_MessageReceived;
                this._tcpListener.Start();                   
                this._running = true;
                this._connectionThread = new Thread(new ThreadStart(ListenForClientConnections));
                this._connectionThread.Start();
                this._connectionThread.IsBackground = true;
                this.MessageReceived += TCPServer_MessageReceived;
            }
        }           
        catch (Exception ex)
        {
        }
    }        

    /// <summary>
    /// Stops the tcplistener
    /// </summary>
    public void Stop()
    {
        if (this._running)
        {
            this._tcpListener.Stop();
            this._tcpListener = null;
            this._running = false;
        }
    }

    public bool Running()
    {
        return this._running;
    }

    public void StopListening()
    {
        try
        {
            lock (this)
            {
                if (this._running)
                {
                    this._tcpListener.AcceptTcpClient().Close();
                    _running = false;
                }
            }
        }
        catch (Exception ex)
        {
        }
    }

    /// <summary>
    /// Thread body for listening for client connections
    /// </summary>
    private void ListenForClientConnections()
    {
        try
        {
            while (this._running)
            {
                lock (this)
                {
                    TcpClient connectedTcpClient = this._tcpListener.AcceptTcpClient();
                    this._bgwListener = new BackgroundWorker();
                    this._bgwListener.DoWork += _bgwListener_DoWork;
                    this._bgwListener.WorkerReportsProgress = true;
                    this._bgwListener.ProgressChanged += _bgwListener_ProgressChanged;
                    this._bgwListener.RunWorkerAsync(connectedTcpClient);
                }
            }
        }
        catch (Exception ex)
        {
        }
    }



    /// <summary>
    /// background worker listens to messages sent by clients. Categorises them based on messages/commands/applicationcommands/
    /// progress response etc..
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private TcpClient clientGUI = null;
    private Queue<string> messageQueue = new Queue<string>();
    private void _bgwListener_DoWork(object sender, DoWorkEventArgs e)        
    {           
        TcpClient client = e.Argument as TcpClient;
        BackgroundWorker bgWorker = sender as BackgroundWorker;

        if (client != null)
        {
            try
            {
                while (this._running)
                {
                    // Block until an instance Message is received 

                   string message = this._bFormatter.Deserialize(client.GetStream()).ToString();

                    if (message.Equals("GUI", StringComparison.InvariantCultureIgnoreCase)
                    {
                        // Chek for first message from tcp client, if it is GUI then store it in a member variable, if you have multiple cleints then use a dictionary
                        clientGUI = client;
                    }

                    if(!clientGUI.Equals(client))
                    {
                        lock (syncobject)
                        {                   
                            messageQueue.Enqueue(message);                 
                        }
                    }                       

                }
            }
            catch (Exception ex)
            {
            }

        }
    }

    /// <summary>
    /// Thread that continuously monitors the message queue for messages and 
    /// sends them to clients
    /// </summary>
    private void ReadQueue()
    {
        try
        {
            while (true)
            {
                try
                {
                    TCPMessage message = null;

                    if (messageQueue.Count > 0)
                    {                          
                        lock (syncobject)
                        {
                            message = messageQueue.Dequeue();                               
                        }

                        if (!string.IsNullOrEmpty(message) && clientGUI != null)
                        {
                            SendMessage(clientGUI, message);
                        }

                    }
                    else { Thread.Sleep(10); }
                }
                catch (Exception ex)
                {
                }
            }
        }
        catch (Exception ex)
        {

        }           
    }


    private MessageReceivedEventHandler _messageReceived;
    public event MessageReceivedEventHandler MessageReceived
    {
        add { _messageReceived += value; }
        remove { _messageReceived -= value; }
    }

    private EventHandler<MessageEventArgs> _serverMessageSent;

    public event EventHandler<MessageEventArgs> ServerMessageSent
    {
        add { _serverMessageSent += value; }
        remove { _serverMessageSent -= value; }
    }


    private void SendMessage(TcpClient client, TCPMessage message)
    {
        try
        {
            lock (syncsendmessageobject)
                _bFormatter.Serialize(client.GetStream(), message);
        }
        catch (Exception ex)
        {
        }
    }       
}