2015-06-17 6 views
1

У меня есть аппаратный компонент, который я использую с помощью связи TCP. Класс, управление имеет 3 рабочие места: Trigger устройство, прослушивать входящие сообщения и поднять 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 
    } 
} 

Этот класс используется в цикле внутри 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 (вне слушателя событий).

+0

Вы уже устанавливаете 'hardwareResult', вы не можете просто ссылаться на это? Если ваш блок 'WaitOne' выполняется перед вашим обработчиком событий, возможно, вы могли бы просто поместить свой код внутри метода« hardware_OnHardwareMessage »вместо внутри блока« WaitOne »? –

+0

@MikeEason вот что я делаю сейчас, но в случае нескольких прослушивателей событий было бы неплохо не обрабатывать все эти поля. и, к сожалению, я не могу поместить свой код внутри обработчика события, так как результат используется и используется некоторыми другими полями – Yoav

ответ

0

Я бы не основывал это на событиях. Возможно, ваш слушатель должен выставить BlockingCollection, который представляет входящий поток сообщений. Читатели могут затем взять из этой коллекции тайм-аут. Если таймаут не ударит, сообщение не будет принято и потеряно (это состояние гонки, которое у вас есть прямо сейчас).

Если вы настаиваете на использовании события использовать замыкание нити в состояние сообщения:

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

    hardware.OnHardwareMessage += handler; 

Таким образом, вам нужно только локальную переменную, которая контекстными более плотно, чем в поле.

Существует обычная ошибка TCP: вы предполагаете, что прочитали целое сообщение. Вы могли бы читать по одному байту за раз.

Смежные вопросы