了解ZMODEM协议



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

以下是规范供参考。

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

在我看来,这份文件中有很多重要的东西没有定义:

  • 它经常提到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,我确实得到了0x323A251DD。但现在我们最后没有任何[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框架:[186B]。这个相框有多长?CRC数据在哪里?是CRC16还是CRC32?规范中没有对其进行定义
  • MSDN文章指定[186B]后面应该跟[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帧一样有意义。

我的伙伴想知道你是否正在实现一个时间机器

我不知道我能不能回答你所有的问题——我从来没有实际上我不得不自己实现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连接传输文件)。

还有许多其他实现,包括免费代码上列出的几个软件,包括qodem,syncterm、MBSE等。我相信syncterm实现是作为库编写的,可能相当容易从您自己的代码中使用(但我不确定)。

如果您浏览旧的MS-DOS软件。

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

填充字节(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-2CR LF XON。为什么[LF]设置了位0x80?

不确定。从Tera项中,我得到了两个控制字符与0x80(8D 8A 11)异或

我们有了第一个神秘的ZCRCW框架:[186B]。这个相框有多长?CRC数据在哪里?是CRC16还是CRC32?规范中没有对其进行定义

ZCRCW不是一个标题或帧类型,它更像是一个脚注,告诉接收者下一步要做什么。在这种情况下,它是包含文件名的数据子包的页脚。它将是一个32位校验和,因为你使用的是";C";键入二进制标头。

  • ZDLEC类型F3/P0 F2/P1 F1/P2 F0/P3CRC-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编码的)

ZDLE+ZBIN(0x18 0x41)表示帧是带二进制数据的CRC-CCITT(XMODEM 16)。ZDLE+ZHEX(0x18 0x42)表示具有十六进制数据的CRC-CCITT(XMODEM 16)。

HEX数据很棘手,因为一开始有些人不理解它。每两个字节,ASCII字符代表一个二进制字节。例如,0x30 0x45 0x41 0x32意味着0x30 0x45,0x41 0x32,或者在ASCII 0 E A 2中,然后是0x0E,0xA2。他们将二进制的两个半字节扩展为ASCII表示。我在几个数据记录器中发现,一些设备使用小写字母来表示HEX中的A~F(A~F),这并不重要,但在这些数据记录器上,你不会找到0x30 0x45 0x41 0x32(0EA2),而是0x30 0x65 0x61 0x32(0 ea2),它不会改变任何事情,只是一开始让它有点混乱。

是的,ZBIN或ZHEX的CRC16是CRC-CCITT(XMODEM)。ZDLE ZBIN32(0x18 0x43)或ZDLE ZBIN 32(0x180 0x44)使用CRC-32计算。

注意,ZDLE和后面的字节在CRC计算中被排除在外。

我正在挖掘ZMODEM,因为我需要";谈话;对于一些电梯门板,一次编程一组新的参数,而不是使用他们的软件逐个属性地更改。这个";谈话;可以坐在长椅上,而不是坐在电梯轿厢顶部,拿着笔记本。那些董事会说ZMODEM,但由于我没有他们期望的数据包格式,董事会仍然拒绝我的文件传输。单板发送0x2a 0x2a 0x18 0x42 0x30 0x31 0x30(x6)+crc,Tera终端在ZMODEM中传输文件发送到单板0x2a 0x2a 0x8 0x42 x30 0x30…+CRC,我不知道为什么0x4B后面的00或01意味着什么。电脑会发送此信息、文件名和一些文件属性。几秒钟后,董事会回答";没有收到文件";。。。

最新更新