Ошибка DrvCnlBasic

Просмотр 15 сообщений - с 31 по 45 (из 65 всего)
  • Автор
    Сообщения
  • #39216
    Mikhail
    Модератор

    > Он должен был остаться в буфере и по окончании сессии очищен.
    Если данные ещё не дошли, то и очищены быть не могут.

    > Я правильно понимаю, что в текущей реализации это проблема System.Net.Sockets.NetworkStream и не лечится ?
    Дело не в текущей реализации. Так работает TCP.
    1. При настройке решаем, сколько времени будем ждать ответа.
    2. Если не дождались нормального ответа, то устанавливаем статус устройства в ошибку и данные очищаются из буфера. Но в буфер могли прийти ещё не все данные, которые отправило устройство. Можно на уровне драйвера попробовать в своём коде подождать подольше и только затем очистить буфер — если так будет лучше, можно в канале связи реализовать.
    3. Если приходит мусор, то надёжнее будет переподключиться.

    #39217
    Mikhail
    Модератор

    Из кода драйвера можно проверить, какой канал связи используется.

    #39226
    manjey73
    Участник

    @mikhail я пытался всеми правдами и неправдами по примерам из интернет при такой ситуации вычитать буфер в никуда в коде DrvCnlBasic, чтобы на следующей сессии все началось с начала.
    Никакого результата это не дало.
    Вся надежда на вас :), у меня не получилось.

    Данные не могут не прийти, ведь обрыва связи на самом деле не было, я просто специально для имитации уменьшал timeout ожидание ответа, и это сразу дает такой результат. Соответственно подобный же результат будет при реальной задержки ответа.

    вчера полдня убил на различные варианте по очистке буфера из интернетов.

    #39241
    manjey73
    Участник

    Некоторые варианты очистки буфера начинают ругаться на то, что нет поддержки такого кода в C# 7.3 ибо netstandard 2.0 а не скажем NET8.
    И вообще, +- интернет предлагает похожие решения. Типа извините, NetworkStreem не предлагает вариант Flush, так как оно тут ничего не делает, и лучший способ это переоткрыть клиента.

    • Ответ изменён 12 месяцев назад пользователем manjey73.
    #39267
    Mikhail
    Модератор

    Идея очистки такая

    if (Connection is TcpConnection tcpConn)
    {
      try
      {
        tcpConn.ClearNetStream(inBuf);
        // или даже лучше с ожиданием таймаута используйте tcpConn.ReadAvailable(...)
        // или просто tcpConn.Read(...)
      }
      catch()
      {
        // здесь вывод в лог
      }
    }

    Буфер свой заведите любой длины. Потребуется добавить зависимость на драйвер канала связи.

    • Ответ изменён 11 месяцев, 4 недели назад пользователем Mikhail.
    • Ответ изменён 11 месяцев, 4 недели назад пользователем Mikhail.
    #39270
    Mikhail
    Модератор

    Даже обычное чтение будет забирать данные из буфера — главное не выпасть из Session по исключению. Это, возможно, самый простой способ — вызывать Read.

    #39274
    manjey73
    Участник

    Потребуется добавить зависимость на драйвер канала связи.

    Имеете ввиду добавить DrvCnlBasic в зависимость и тогда пробовать чистить буфер?
    Вернее писать его в никуда так понимаю между запросами ?

    #39290
    Mikhail
    Модератор

    Чтобы класс TcpConnection был виден, потребуется добавить зависимость на DrvCnlBasic в свой проект.
    Попробуйте просто обычное чтение выполнить для очистки буфера, если обнаружено нарушение формата данных.

    #39293
    manjey73
    Участник

    Спасибо, попробую. Как доберусь. А то тут за ModAlarm взялся для дальнейших переделок 🙂

    #39389
    manjey73
    Участник
    2025-07-10 15:59:30 Сеанс связи с устройством [49] Mbus_SDM
    Отправка (5): 10 40 FD 3D 16
    Отправка (9): 68 03 03 68 53 01 B1 05 16
    Приём (4/4): 68 90 90 68
    Приём (52/146): 08 01 72 ........
    Ошибка: некорректная длина ответа!
    Получено за 1013 мс
    
    2025-07-10 16:00:00 Сеанс связи с устройством [49] Mbus_SDM
    Отправка (5): 10 40 FD 3D 16
    Отправка (9): 68 03 03 68 73 01 B1 25 16
    Приём (4/4): 82 09 0A FD
    Приём (11/11): 3A 82 09 0A FD 3A 00 00 0A FD 3A
    Ошибка: некорректная длина ответа!
    Read 159   -  Приём (159/1024): 00 00 0A FD ........
    Получено за 1638 мс
    

    стер длинный набор буков. Но суть, если произошло дочитывание, то следующая сессия начинается с начала
    Но почему-то не всегда происходит дочитка.
    Код такой

            private void ClearTcpConnection()
            {
                if (Connection is TcpConnection tcpConn)
                {
                    try
                    {
                        //tcpConn.ClearNetStream(buf_in);
                        // или даже лучше с ожиданием таймаута используйте tcpConn.ReadAvailable(...)
                        // или просто tcpConn.Read(...)
    
                        Thread.Sleep(10);
                        string log = "";
                        byte[] buffer = new byte[1024];
    
                        while (tcpConn.NetStream.DataAvailable) // && totalWait < 1000
                        {
                            int read = tcpConn.Read(buffer, 0, buffer.Length, 1000, ProtocolFormat.Hex, out log);
    
                            Log.WriteLine($"Read {read}   -  {log}" );
                            if (read == 0) break; // Соединение закрыто
                        }
                        readcnt = 0; // Не знаю, надо или нет обнулять?
                    }
                    catch (Exception ex)
                    {
                        // здесь вывод в лог
                        throw new ScadaException((Locale.IsRussian ? "Ошибка при очистке потока данных: " : "Error clearing data stream: ") + ex.Message, ex);
                    }
                }
            }
    

    пока на больше у меня тямы не хватило

    #39390
    manjey73
    Участник

    tcpConn.ReadAvailable читает кусками, потому что tcpConn.NetStream.DataAvailable становится false.

    Как тут сделать цикл, чтобы прочесть даже есть оно false ? но не больше заложенного буфера ?

    #39391
    manjey73
    Участник
            private void ClearTcpConnection(int bufLength)
            {
                if (Connection is TcpConnection tcpConn)
                {
                    try
                    {
                        string log = "";
                        byte[] buffer = new byte[bufLength - readcnt];
    
                        int totalWait = 0;
                        int totalRead = 0;
    
                        while (totalRead < buffer.Length && totalWait < PollingOptions.Timeout)
                        {
                            int read = tcpConn.ReadAvailable(buffer, 0, buffer.Length, ProtocolFormat.Hex, out log);
    
                            // Log.WriteLine($"Read {read} DataAvailable {tcpConn.NetStream.DataAvailable} \n{log}"); // TEST
    
                            Thread.Sleep(50);
                            totalWait += 50;
                            totalRead += read;
                        }
                    }
                    catch (Exception ex)
                    {
                        // здесь вывод в лог
                        throw new ScadaException((Locale.IsRussian ? "Ошибка при очистке потока данных: " : "Error clearing data stream: ") + ex.Message, ex);
                    }
                }
            }
    

    В общем сварганил такое вот, может поправите в чем. Передаю размер буфера (тут может не совсем правильно) и отнимаю потом уже принятое.

    • Ответ изменён 11 месяцев, 2 недели назад пользователем manjey73.
    #39393
    manjey73
    Участник

    Косяк в том, что DataAvailable почему-то не всегда true.
    Как будто в буфер данные поступают порциями, а не целиком, раз они поступили.
    Как такое может быть?

    #39406
    Mikhail
    Модератор

    tcpConn.ReadAvailable читает кусками, потому что tcpConn.NetStream.DataAvailable становится false.
    Как будто в буфер данные поступают порциями, а не целиком, раз они поступили.

    Так и есть. Данные поступают порциями, скорее всего потому, что протокол TCP их разбивает на куски. Поэтому дочитку делать, наверное, придётся по таймауту, а не по наличию данных. То есть дочитываем 1 секунду, например. Что пришло позже — уже не считаем и буфер забьётся.

    #39407
    manjey73
    Участник

    Понятно. В случае, если можно посчитать сколько данных должно быть, можно по счетчику. В остальных случаях по сути второй таймаут.. Ну хотя бы между сессиями точно чистит, потому что ClearNetStream(inBuf) почему-то не очищает, хотя вроде должен бы.

Просмотр 15 сообщений - с 31 по 45 (из 65 всего)
  • Для ответа в этой теме необходимо авторизоваться.