У меня странный вопрос, который включает NetworkStreams в C#. Net Core 2.2.101
Моя настройка следующая:
- У меня есть список метров
- Каждый метр имеет список регистров (регистр сохраняет значение, например: напряжение или ток)
- Измерители подключены к модему GSM через RS485 (не имеет значения для вопроса)
- Я посылаю команды модему для чтения определенных c регистров для указанных c метров
Для каждого регистра каждого счетчика я посылаю команду, используя stream.Write(bytesToSend, 0, bytesToSend.Length);
, чтобы попросить счетчик выслать мне данные, которые сохранены в указанном регистре c счетчика. Сразу после отправки я прочитал ответ, используя stream.Read(buffer, 0, buffer.Length);
. Я также установил read timeout 5 секунд, который будет блокировать и ждать 5 секунд, прежде чем перейти к следующему регистру, если до тайм-аута не было получено никакого ответа.
Проблема:
Что происходит, когда я запрашиваю данные у счетчика, иногда это занимает слишком много времени, и время ожидания истекает, после чего я перехожу к следующему регистру для запроса data, но иногда первый регистр ответит данными после того, как я перейду к следующему регистру (это означает, что NetworkStream теперь имеет данные из предыдущего регистра). Поскольку в моем for
-l oop я уже перешел, моя программа считает, что данные, которые я читаю из потока, предназначены для текущего регистра, тогда как на самом деле это данные для предыдущего регистра предыдущей итерации. Это портит данные, которые поступают в базу данных, потому что я сохраняю неправильное значение для неправильного регистра.
Мой вопрос: есть ли умный способ игнорировать любые входящие данные из предыдущей итерации в моем for
-l oop? К сожалению, в полученных данных нет информации, которую можно было бы использовать для определения, для какого регистра эти данные нужны.
Вот фрагмент того, что мой запросы на запись и чтение выглядят следующим образом:
stream.ReadTimeout = 5000;
stream.WriteTimeout = 2000;
foreach (Meter meter in metersToRead)
{
foreach (Register register in meter.Registers)
{
// Write the request to the meter
stream.Write(bytesToSend, 0, bytesToSend.Length);
// Read response from meter
requestedReadingDataCount = stream.Read(buffer, 0, buffer.Length);
// Extract the value from the response buffer and save the value to the database
...
}
}
Я хочу попытаться клонировать поток и использовать клонированный поток для связи относительно текущей итерации регистра, чтобы при поступлении ответа после того, как я закрыл клонированный поток и перешел к следующему регистру, ответ не удастся, так как поток был закрыт. Однако я не уверен, что вы можете клонировать C# NetworkStream? Кто-нибудь знает?
Мое последнее средство будет сделать вызов в базу данных после того, как я прочитал данные для каждого регистра, чтобы проверить, являются ли полученные мной данные приемлемыми для этого регистра, но я боюсь, что это может замедлить работу программы со всеми вызовами базы данных, и мне придется создать некоторые правила, которые будут определять, является ли значение разумным для текущего регистра.
Любые идеи будут высоко оценены. Если у вас есть какие-либо вопросы, пожалуйста, дайте мне знать, и я постараюсь объяснить это подробнее.
Редактировать
Вот обновленный фрагмент кода, а также изображение, которое лучше объяснит проблема, которая у меня возникла.
private async Task ReadMeterRegisters(List<MeterWithRegisters> metersWithRegisters, NetworkStream stream)
{
stream.ReadTimeout = 5000; /* Read timeout set to 5 seconds */
stream.WriteTimeout = 2000; /* Write timeout set to 2 seconds */
foreach (Meter meter in metersToRead)
{
foreach (Register register in meter.Registers)
{
// Instantiate a new buffer to hold the response
byte[] readingResponseDataBuffer = new byte[32];
// Variable to hold number of bytes received
int numBytesReceived = 0;
try
{
// Write the request to the meter
stream.Write(bytesToSend, 0, bytesToSend.Length);
// Read response from meter
numBytesReceived = stream.Read(buffer, 0, buffer.Length);
}
catch (IOException) /* catch read/write timeouts */
{
// No response from meter, move on to next register of current meter
continue;
}
// Extract the value from the response buffer and save the value to the database
...
}
}
}