обработка последовательного порта вопроса/ответа в C#

Хорошо, вот проблема (это связано с моим предыдущим постом)

Мне нужно иметь систему вопросов/ответов для последовательных сообщений, которая работает примерно так:

вопрос: привет ответ: мир? вопросы: нет, здравствуйте медсестра ответ: ну вы не весело.

это означало бы, что я говорю «привет», ожидается, что удаленное устройство отправит обратно «мир?» в течение некоторого периода времени, и если это не так, у меня должен быть способ получить доступ к этому буферу, так что вот что я думаю, пожалуйста, дайте мне отзыв

a ReaderWriterLock'd 'readBuffer' Метод задачи, который будет записывать в поток Метод ответа, который будет наблюдать за readBuffer, пока он не будет содержать то, что я ожидаю, или пока не истечет время ожидания.

во-первых, как сообщество stackoverflow спроектирует этот класс, во-вторых, как они будут писать событие datareceived? В-третьих, как сделать этот код более надежным, чтобы несколько экземпляров класса могли существовать в параллельных потоках для одновременной связи?


person Firoso    schedule 24.03.2009    source источник
comment
у меня должен быть способ получить доступ к этому буферу, какой буфер?   -  person Autodidact    schedule 24.03.2009


Ответы (2)


В основном это проблема производитель-потребитель, так что это должно быть основой для общего дизайн.

Вот некоторые мысли по этому поводу:

a) Буфер FIFO (очередь)

Прежде всего, у вас должен быть экземпляр потокобезопасной очереди (буфера FIFO) для каждого экземпляра вашего класса. Один поток будет получать данные и заполнять их, в то время как другой будет читать данные потокобезопасным способом. Это означает только то, что вам придется использовать блокировку для каждой операции постановки/удаления из очереди.

FIFO Queue позволит вам одновременно обрабатывать данные в рабочем потоке и заполнять их из коммуникационного потока. Если вам нужно получить много данных, вы можете удалить некоторые данные из очереди в рабочем потоке и проанализировать их до того, как все они будут получены. В противном случае вам нужно будет подождать, пока все данные не будут получены, чтобы проанализировать их все сразу. В большинстве случаев вы не знаете, сколько данных вы должны получить, пока не начнете анализировать их.

b) Рабочий поток ожидает данных

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

c) Абстракция порта

Чтобы обрабатывать разные типы портов, вы можете обернуть свой последовательный порт внутри интерфейса, который может иметь как минимум эти методы (могу я что-то забыть):

 interface IPort
 { 
      void Open();
      void Close();
      event EventHandler<DataEventArgs> DataReceived;
      void Write(Data data);
 }

Это поможет вам отделить конкретный код связи от конечного автомата.

ПРИМЕЧАНИЕ. (согласно Microsoft) Событие DataReceived не гарантируется для каждого полученного байта. Используйте свойство BytesToRead, чтобы определить, сколько данных осталось прочитать в буфере. Таким образом, вы можете создать свою собственную реализацию IPort, которая будет регулярно опрашивать SerialPort, чтобы гарантировать, что вы не пропустите ни одного байта (есть вопрос о SO, который уже решает эту проблему).

г) Получение данных

Чтобы получить данные, вам нужно будет прикрепить обработчик для события IPort.DataReceived (или SerialPort.DataReceived, если вы его не упаковываете) и поставить полученные данные в очередь внутри обработчика. В этом обработчике вы также должны установить упоминание ManualResetEvent для уведомления рабочего потока о получении новых данных.

person Groo    schedule 24.03.2009
comment
Это та обратная связь, которую я хотел, хотя я не уверен, зачем нужен буфер FIFO, я определенно понимаю его использование. В своих экспериментах я использую stringbuilder. - person Firoso; 24.03.2009
comment
Например, если вам нужно проанализировать [length][item(1)][item(2)]...[item(n)], где [length] — количество элементов, вы можете исключить информацию о длине из очереди. как только вы его получите, подготовьте и распределите свои данные по элементам, пока очередь заполняется. - person Groo; 24.03.2009
comment
Это хороший ответ. Я бы посоветовал изучить ConcurrentQueue‹T› для реализации вашей очереди FIFO. - person gonzobrains; 04.04.2013

У меня была аналогичная проблема с дизайном, когда я писал асинхронный прослушиватель сокетов для форматированных данных. Перевод того, что я придумал в модель SerialPort/DataReceived, будет примерно таким:

Основной класс инкапсулирует систему вопроса/ответа — он будет содержать логику для генерации ответа на основе ввода. Каждый экземпляр класса будет привязан к одному последовательному порту, который можно установить во время или после создания. Будет метод типа StartCommunications — он будет связывать событие DataReceived с другим методом в классе. Этот метод отвечает за захват данных из порта и определение того, пришло ли полное сообщение. Если это так, он вызывает свое собственное событие (определенное в классе), к которому будет привязан соответствующий метод. Вы также можете сделать так, чтобы он вызывал предопределенный метод в вашем классе вместо вызова события — я определил событие для повышения гибкости.

Этот базовый дизайн отлично работает в производственной системе и может обрабатывать больше входных данных, чем остальные системы, подключенные к нему.

person Harper Shelby    schedule 24.03.2009