15

我需要在我的程序中包含基本的文件发送和文件接收例程,并且它需要通过 ZMODEM 协议。问题是我无法理解规范。

作为参考,这里是规范

规范没有定义各种常量,所以这里有一个来自 Google 的头文件

在我看来,该文档中有很多未定义的重要内容:

  • 它经常提到 ZDLE 编码,但它是什么?我究竟什么时候使用它,什么时候不使用它?
  • 在 ZFILE 数据帧之后,传输文件的元数据(文件名、修改日期、大小等)。其后是 ZCRCW 块,然后是根据规范未定义类型的块。ZCRCW 块据称包含 16 位 CRC,但规范没有定义计算 CRC 的数据。
  • 它没有定义它使用的 CRC 多项式。我偶然发现 CRC32 poly 是标准的 CRC32,但我对 CRC16 poly 没有这样的运气。没关系,我是通过反复试验找到的。CRC16 多边形是 0x1021。

我四处寻找参考代码,但我能找到的都是 90 年代初的不可读、未记录的 C 文件。我还从 MSDN 中找到了这组文档,但它与我运行的测试非常模糊和矛盾:http: //msdn.microsoft.com/en-us/library/ms817878.aspx(您可能需要通过谷歌的缓存查看)

为了说明我的困难,这里有一个简单的例子。我在服务器上创建了一个包含“Hello world!”的纯文本文件,它被称为 helloworld.txt。

我使用以下命令从服务器启动传输:

sx --zmodem helloworld.txt

这会提示服务器发送以下 ZRQINIT 帧:

2A 2A 18 42 30 30 30 30 30 30 30 30 30 30 30 30   **.B000000000000
30 30 0D 8A 11                                    00.Š.

与此有关的三个问题:

  • 填充字节(0x2A)是任意的吗?为什么这里有两个,但在其他情况下只有一个,有时甚至没有?
  • 规范最后没有提到 [CR] [LF] [XON],但 MSDN 文章提到了。为什么会在那里?
  • 为什么 [LF] 设置了位 0x80?

在此之后,客户端需要发送一个 ZRINIT 帧。我从 MSDN 文章中得到了这个:

2A 2A 18 42 30 31 30 30 30 30 30 30 32 33 62 65   **.B0100000023be
35 30 0D 8A                                       50.Š

除了 [LF] 0x80 标志问题之外,我还有两个问题:

  • 为什么这次不包括[XON]?
  • CRC 是根据二进制数据还是 ASCII 十六进制数据计算的?如果是二进制数据,我得到 0x197C,如果是 ASCII 十六进制数据,我得到 0xF775;这些都不是框架中的实际内容(0xBE50)。(已解决;它遵循您使用的任何模式。如果您处于 BIN 或 BIN32 模式,则为二进制数据的 CRC。如果您处于 ASCII 十六进制模式,则为 ASCII 十六进制字符表示的内容的 CRC .)

服务器以 ZFILE 帧响应:

2A 18 43 04 00 00 00 00 DD 51 A2 33               *.C.....ÝQ¢3

好的。这是有道理的。如果我计算 [04 00 00 00 00] 的 CRC32,我确实得到 0x33A251DD。但是现在我们最后没有任何 [CR] [LF] [XON]。为什么是这样?

在这一帧之后,服务器也会立即发送文件的元数据:

68 65 6C 6C 6F 77 6F 72 6C 64 2E 74 78 74 00 31   helloworld.txt.1
33 20 32 34 30 20 31 30 30 36 34 34 20 30 20 31   3 240 100644 0 1
20 31 33 00 18 6B 18 50 D3 0F F1 11                13..k.PÓ.ñ.

这甚至没有标题,它只是直接跳转到数据。好吧,我可以忍受。然而:

  • 我们有了第一个神秘的 ZCRCW 框架:[18 6B]。这个框架有多长?CRC 数据在哪里,是 CRC16 还是 CRC32?它没有在规范中的任何地方定义。
  • MSDN 文章指定 [18 6B] 后面应该跟 [00],但事实并非如此。
  • 然后我们有一个未定义类型的帧:[18 50 D3 0F F1 11]。这是一个单独的框架还是 ZCRCW 的一部分?

客户端需要使用 ZRPOS 帧进行响应,同样取自 MSDN 文章:

2A 2A 18 42 30 39 30 30 30 30 30 30 30 30 61 38   **.B0900000000a8
37 63 0D 8A                                       7c.Š

与 ZRINIT 帧相同的问题:CRC 错误,[LF] 设置了位 0x80,并且没有 [XON]。

服务器响应一个 ZDATA 帧:

2A 18 43 0A 00 00 00 00 BC EF 92 8C               *.C.....¼ï’Œ

与 ZFILE 相同的问题:CRC 一切正常,但 [CR] [LF] [XON] 在哪里?

在此之后,服务器发送文件的有效负载。由于这是一个简短的示例,它适合一个块(最大大小为 1024):

48 65 6C 6C 6F 20 77 6F 72 6C 64 21 0A            Hello world!.

从文章似乎提到的内容来看,有效载荷是用 [ZDLE] 转义的。那么如何传输恰好与 [ZDLE] 的值匹配的有效负载字节呢?还有其他类似的价值观吗?

服务器以这些帧结束:

18 68 05 DE 02 18 D0                              .h.Þ..Ð
2A 18 43 0B 0D 00 00 00 D1 1E 98 43               *.C.....Ñ.˜C

我完全迷失在第一个。第二个与 ZRINIT 和 ZDATA 帧一样有意义。

4

2 回答 2

7

我的朋友想知道您是否正在实施时间机器。

我不知道我能回答你所有的问题——我实际上从来没有自己实现过 zmodem——但这里有几个答案:

从文章似乎提到的内容来看,有效载荷是用 [ZDLE] 转义的。那么如何传输恰好与 [ZDLE] 的值匹配的有效负载字节呢?还有其他类似的价值观吗?

您在问题开头链接到的文档中明确解决了这一点,该文档说:

The ZDLE character is special.  ZDLE represents a control sequence
of some sort.  If a ZDLE character appears in binary data, it is
prefixed with ZDLE, then sent   as ZDLEE.

它经常提到 ZDLE 编码,但它是什么?我究竟什么时候使用它,什么时候不使用它?

在过去,某些“控制字符”被用来控制通信通道(因此得名)。例如,发送 XON/XOFF 字符可能会暂停传输。ZDLE 用于转义可能有问题的字符。根据规范,这些是默认转义的字符:

ZMODEM software escapes ZDLE, 020, 0220, 021, 0221, 023, and 0223.
If preceded by 0100 or 0300 (@), 015 and 0215 are also escaped to
protect the Telenet command escape CR-@-CR.  The receiver ignores
021, 0221, 023, and 0223 characters in the data stream.

我四处寻找参考代码,但我能找到的都是 90 年代初的不可读、未记录的 C 文件。

这是否包括lrzsz包的代码?这在大多数 Linux 发行版上仍然广泛可用(并且对于通过已建立的 ssh 连接传输文件非常方便)。

还有许多其他实现,包括freecode上列出的软件中的几个,包括qodemsynctermMBSE等。我相信syncterm 实现是作为库编写的,可以从您自己的代码中轻松使用(但我不确定)。

如果您浏览旧的 MS-DOS 软件集合,您可能会发现其他代码。

于 2012-03-14T20:54:16.213 回答
4

我不能怪你。用户手册没有以用户友好的方式组织

填充字节(0x2A)是任意的吗?

不,从第 14,15 页开始:

二进制标头以序列 ZPAD、ZDLE、ZBIN 开头。

十六进制标题以序列 ZPAD、ZPAD、ZDLE、ZHEX 开头。

.

规范最后没有提到 [CR] [LF] [XON],但 MSDN 文章提到了。为什么会在那里?

第 15 页

* * ZDLE B 型 F3/P0 F2/P1 F1/P2 F0/P3 CRC-1 CRC-2 CR LF XON 。为什么 [LF] 设置了位 0x80?

没有把握。从 Tera 术语我得到两个控制字符与 0x80 (8D 8A 11) 异或

我们有了第一个神秘的 ZCRCW 框架:[18 6B]。这个框架有多长?CRC 数据在哪里,是 CRC16 还是 CRC32?它没有在规范中的任何地方定义。

ZCRCW 不是标头或帧类型,它更像是告诉接收器接下来会发生什么的页脚。在这种情况下,它是包含文件名的数据子包的页脚。这将是一个 32 位校验和,因为您使用的是“C”类型的二进制标头。

  • ZDLE C TYPE F3/P0 F2/P1 F1/P2 F0/P3 CRC-1 CRC-2 CRC-3 CRC-4

.

然后我们有一个未定义类型的帧:[18 50 D3 0F F1 11]。这是一个单独的框架还是 ZCRCW 的一部分?

这就是 ZCRCW 数据子包的 CRC。它是 5 个字节,因为第一个是 0x10,一个需要 ZDLE 转义的控制字符。我不确定 0x11 是什么。

并且没有 [XON]。

XON 仅适用于十六进制标头。您不要将它用于二进制标头。

  • ZDLE A 型 F3/P0 F2/P1 F1/P2 F0/P3 CRC-1 CRC-2 。那么如何传输恰好与 [ZDLE] 的值匹配的有效负载字节呢?

18 58(又名 ZDLEE)

18 68 05 DE 02 18 D0

那是数据子帧的页脚。接下来的 5 个字节是 CRC(最后一个字节是 ZDLE 编码的)

于 2015-03-31T17:59:28.757 回答