Реализация ZModem в C # - Проблемы с большими файлами, вызванные ZPOS - PullRequest
0 голосов
/ 28 ноября 2018

У меня проблема с моей реализацией ZModem, когда я пытаюсь отправить файлы размером более 16 КБ.

Я проследил связь с WireShark, а также сравнил свои данные с отправляемым TeraTerm.

TeraTerm, например, способен отправлять файлы любого размера.Проблема, с которой я сталкиваюсь, заключается в том, что в какой-то момент приемное устройство отправляет мне запрос ZPOS обратно.

Когда я пытаюсь повторно отправить данные из заданного смещения, мой поток данных поврежден.Каждый последующий пакет данных приводит к ответу ZPOS.

Вот полный обмен данными, которые я отслеживал с помощью WireShark.

Вызов приемника с помощью команды rz\r.

0000   1b 00 30 b5 45 fb 01 a2 ff ff 00 00 00 00 09 00   ..0µEû.¢ÿÿ......
0010   00 03 00 14 00 01 03 03 00 00 00 72 7a 0d         ...........rz.

Инициирование сеанса

0000   1b 00 70 b1 f0 15 02 a2 ff ff 00 00 00 00 09 00   ..p±ð..¢ÿÿ......
0010   00 03 00 14 00 01 03 14 00 00 00 2a 2a 18 42 30   ...........**.B0
0020   30 30 30 30 30 30 30 30 30 30 30 30 30 0d 0a      0000000000000..

Ответ от устройства

0000   1b 00 90 01 5b fb 01 a2 ff ff 00 00 00 00 09 00   ....[û.¢ÿÿ......
0010   01 03 00 14 00 81 03 15 00 00 00 2a 2a 18 42 30   ...........**.B0
0020   31 30 30 30 30 30 30 32 33 62 65 35 30 0d 8a 11   100000023be50...

Затем я отправляю заголовок файла с именем файла и информацией о файле.

0000   1b 00 b0 fa b3 00 02 a2 ff ff 00 00 00 00 09 00   ..°ú³..¢ÿÿ......
0010   00 03 00 14 00 01 03 0a 00 00 00 2a 18 41 04 00   ...........*.A..
0020   00 01 01 aa 16                                    ...ª.

0000   1b 00 b0 f1 a1 08 02 a2 ff ff 00 00 00 00 09 00   ..°ñ¡..¢ÿÿ......
0010   00 03 00 14 00 01 03 20 00 00 00 73 61 6d 70 6c   ....... ...sampl
0020   65 2e 74 78 74 00 32 31 35 30 31 20 31 33 33 37   e.txt.21501 1337
0030   37 35 30 31 33 33 32 18 6b 83 e5                  7501332.k.å

Ответ от устройства говорит мне этоготов к приему файлов.

0000   1b 00 90 01 5b fb 01 a2 ff ff 00 00 00 00 09 00   ....[û.¢ÿÿ......
0010   01 03 00 14 00 81 03 15 00 00 00 2a 2a 18 42 30   ...........**.B0
0020   39 30 30 30 30 30 30 30 30 61 38 37 63 0d 8a 11   900000000a87c...

После этого я отправляю заголовок ZData и все подпакеты.

0000   1b 00 b0 f1 a1 08 02 a2 ff ff 00 00 00 00 09 00   ..°ñ¡..¢ÿÿ......
0010   00 03 00 14 00 01 03 0b 00 00 00 2a 18 41 18 4a   ...........*.A.J
0020   00 00 00 00 46 ae                                 ....F®

Когда я пытаюсь загрузить файл большего размера, я получаю ответ ZRPOS во времязагрузка.Что касается спецификации ZModem, получатель говорит мне, чтобы возобновить с заданным смещением.

0000   1b 00 90 01 5b fb 01 a2 ff ff 00 00 00 00 09 00   ....[û.¢ÿÿ......
0010   01 03 00 14 00 81 03 15 00 00 00 2a 2a 18 42 30   ...........**.B0
0020   39 30 30 34 30 30 30 30 30 62 35 64 31 0d 8a 11   900400000b5d1...

Но каждый последующий подпакет получает тот же ответ от принимающего устройства.

Вот реализация, которую я сделалкто отвечает за отправку файла.

private void SendZDATAPackets(byte[] src, CRC16CCIT crcCalculator)
{
    // Chunk size
    var chunkSize = 1024;

    // Create ZDATA header
    var zdataHeaderQueue = new Queue<byte>();
    var zdataHeaderCommand = Utils.BuildDataCommand(HeaderType.ZDATA, 0, 0, 0, 0);

    foreach (var c in zdataHeaderCommand)
    {
        zdataHeaderQueue.Enqueue((byte)c);
    }

    // Send ZDATA header
    SendCommand(zdataHeaderQueue.ToArray());

    ResponseHeader zdataResponse = null;

    // Slice binary data into chunks.
    for (int i = 0; i < src.Length; i += chunkSize)
    {
        // Slice data
        var dataSlice = src
            .Skip(i)
            .Take(chunkSize)
            .ToArray();

        // Send ZCRCG, if its the last part of the data send ZCRCE
        var requiredSequence = (i + dataSlice.Length) < src.Length ? ZDLESequence.ZCRCG : ZDLESequence.ZCRCE;

        if (zdataResponse?.ZHeader == HeaderType.ZRPOS)
        {
            /*
             * A ZRPOS header resets the sender's file offset to the correct position.
             * If possible, the sender should purge its output buffers and/or networks
             * of all unprocessed output data, to minimize the amount of unwanted data
             * the receiver must discard before receiving data starting at the correct
             * file offset. The next transmitted data frame should be a ZCRCW frame
             * followed by a wait to guarantee complete flushing of the network's memory.
             */
            SerialPort.DiscardOutBuffer();

            dataSlice = src
                .Skip(zdataResponse.RequestedOffset)
                .Take(chunkSize)
                .ToArray();

            requiredSequence = ZDLESequence.ZCRCW;
        }

        // Create data queue for the sliced data.
        var queue = new Queue<byte>(dataSlice);

        // Calculate CRC
        var dataForCrcCalculation = dataSlice.Concat(new byte[] { (byte)requiredSequence }).ToArray();
        var crc = crcCalculator.ComputeChecksumAsBytes(dataForCrcCalculation);

        // Add crc
        queue.Enqueue((byte)ControlBytes.ZDLE);
        queue.Enqueue((byte)requiredSequence);
        queue.Enqueue(crc[0]);
        queue.Enqueue(crc[1]);

        // Send data
        var zdataCommand = queue.ToArray();
        zdataResponse = SendCommand(zdataCommand);
    }
}

У кого-нибудь была такая же проблема во время реализации, и кто-нибудь мог бы указать мне, как решить эту проблему?

Спасибо!

1 Ответ

0 голосов
/ 08 декабря 2018

На случай, если кому-то понадобится собственная реализация ZModem в C #, мне удалось заставить ее работать сейчас.

Проблема заключалась в том, что у меня не было ZDLE-кодировки для байтов, которые я отправлял.ZModem требует кодировать пакеты данных, а также CRC, присоединенный в конце, для экранирования определенных символов.Однако, если вы используете CRC16, вам не нужно кодирование для CRC.

Я создал GitHub-репозиторий, чтобы любой мог его использовать.Однако функциональность ограничена для загрузки данных на удаленное устройство.Реализация загрузки не должна быть проблемой.

https://github.com/datoml/zmodem-dotnet-standard

...