1

我有一个用于 TCP 通信的硬件组件。控制它的类有 3 个工作:触发设备、监听传入消息并在收到消息event时引发:

public class Hardware
{
    public event Action<string> OnHardwareMessage;
    private NetworkStream stream = new NetworkStream();
    public Hardware()
    {
        Task.Factory.StartNew(() => { Listen(); });
    }

    private void Listen()
    {
        //listen to TCP port and raise an event when a message is received
        byte[] bytes = new byte[1024];
        int bytesRead = stream.Read(bytes, 0, bytes.Length);

        string response = Encoding.ASCII.GetString(bytes, 0, bytesRead);

        if (OnHardwareMessage != null)
            OnHardwareMessage(response);
    }

    public void Trigger()
    {
        //Trigger the hardware component
        //the response usually takes up to 5 seconds to arrive
    }
}

此类在 a 内的循环中使用view-model

public class MainViewModel
{
    private static EventWaitHandle hardwareWaiter =
        new EventWaitHandle(false, EventResetMode.AutoReset);

    private Hardware hardware = new Hardware();

    //what i'm doing now is holding a field for incoming event results
    private string hardwareResult;

    public MainViewModel()
    {
        hardware.OnHardwareMessage += hardware_OnHardwareMessage;

        while (true)
        {
            hardware.Trigger();
            if (hardwareWaiter.WaitOne(10000))
            {
                //is it possible to read the event argument here?

                //do something with the event argument
                someObservableCollection.Add(hardwareResult);

                //clear the value
                hardwareResult = string.Empty;
            }
            else
            {
                throw new Exception("Hardware did not respond on time");
            }
        }
    }

    //event listener for hardware events
    private void hardware_OnHardwareMessage(string message)
    {
        hardwareResult = message;
        hardwareWaiter.Set();
    }
}

我所做的是触发设备并等待长达 10 秒的响应。我现在正在做的是持有一个类范围的字段,分配在事件侦听器内部接收到的消息,在循环内部读取它并清除它。
我的问题是是否有任何内置机制可以让我在EventWaitHandle发出信号后直接读取事件参数(在事件侦听器之外)。

4

1 回答 1

0

我不会以事件为基础。也许您的侦听器应该公开BlockingCollection表示传入消息流的 a 。然后,读者可以在超时后从该集合中获取。如果超时没有消息被接收和丢失(这是你现在拥有的竞争条件)。

如果您坚持使用事件,请使用闭包来处理消息状态:

string hardwareResult = null;
Action handler = (...) =>
    {
        hardwareResult = message;
        hardwareWaiter.Set();
    };

    hardware.OnHardwareMessage += handler;

这样,您只需要一个范围比字段更紧密的局部变量。

还有一个常见的 TCP 错误:您假设阅读了整条消息。您可以一次读取一个字节。

于 2015-06-17T11:07:53.450 回答