文章目录
ZMODEM 接收端实现源码解析:以 rz 示例为例
在嵌入式和串口通信领域,ZMODEM 协议被广泛用于串口文件传输,尤其适用于固件升级、配置传输等场景。相比 XMODEM 和 YMODEM,ZMODEM 拥有流式传输、自动开始、断点续传等优势,是工业环境中较为成熟的一种协议。
本文将通过一份 C 语言编写的 ZMODEM 接收端示例源码,解析其实现逻辑和核心机制,为开发者提供移植和应用该协议的参考。
一、项目概述
该程序是一个模拟 rz
命令功能的示例,运行在类 UNIX 系统中,通过文件接口访问串口设备,实现了较完整的 ZMODEM 协议接收流程。它主要包括以下功能:
- 等待远程 ZMODEM 发送方启动传输;
- 解析协议帧(ZRQINIT、ZFILE、ZDATA、ZEOF、ZFIN 等);
- 支持文件头识别和数据写入;
- 实现错误检测与自动重传(通过 ZRPOS);
- 支持传输取消与中断处理。
二、结构设计与模块划分
1. 串口收发接口
程序将串口抽象为标准文件流 FILE *com
,并实现了 zm_recv()
和 zm_send()
,用于 ZMODEM 协议栈内部调用:
ZRESULT zm_recv() {
uint8_t result;
if (fread(&result, 1, 1, com) == 1)
return result;
else
return CLOSED;
}
ZRESULT zm_send(uint8_t chr) {
int result = fputc((char)chr, com);
return (result == EOF) ? CLOSED : OK;
}
2. 串口初始化
串口设备通过命令行传入(如 /dev/ttyUSB0
),程序通过 fopen()
打开并取消缓冲:
static FILE* init_com(int argc, char **argv) {
FILE *com = fopen(argv[1], "wb+");
setvbuf(com, NULL, _IONBF, 0); // 禁用缓冲
return com;
}
三、ZMODEM 协议核心流程解析
主流程位于 main()
函数中,包含等待初始化、接收头帧、数据帧、终止确认等。
1. 等待传输初始化
程序首先调用 zm_await("rz\r", ...)
等待对端开始 rz 传输过程:
if (zm_await("rz\r", (char*)rzr_buf, 4) == OK) {
// 进入主接收循环
}
2. 接收 ZMODEM 帧头
主循环中调用 zm_await_header()
获取协议帧头并解析:
ZRESULT result = zm_await_header(&hdr);
switch (hdr.type) {
case ZRQINIT:
case ZEOF:
zm_send_flags_hdr(ZRINIT, CANOVIO | CANFC32, 0, 0, 0);
break;
3. 文件头(ZFILE)处理
当接收到 ZFILE
时,调用 zm_read_data_block()
获取文件名,并打开写入文件:
result = zm_read_data_block(data_buf, &count);
out = fopen((char*)data_buf, "wb");
zm_send_pos_hdr(ZRPOS, received_data_size);
4. 数据帧(ZDATA)接收
进入 ZDATA
状态后,程序进入子循环读取数据块,识别结束符号(如 CRCE
、CRCG
、CRCQ
、CRCW
):
while (true) {
result = zm_read_data_block(data_buf, &count);
fwrite(data_buf, count - 1, 1, out);
received_data_size += (count - 1);
if (result == GOT_CRCW || result == GOT_CRCQ) {
zm_send_pos_hdr(ZACK, received_data_size);
}
}
5. 异常与错误处理
如果 CRC 校验失败或其他错误,通过 ZRPOS
回应远程重发:
result = zm_send_pos_hdr(ZRPOS, received_data_size);
goto startframe;
四、协议帧类型说明
帧类型 | 含义 |
---|---|
ZRQINIT | 初始化请求 |
ZRINIT | 初始化响应 |
ZFILE | 文件信息头(文件名) |
ZDATA | 数据块 |
ZEOF | 文件结束 |
ZFIN | 会话结束 |
ZACK | 传输确认 |
ZNAK | 错误响应 |
ZRPOS | 请求重传 |
五、功能总结
本示例实现了以下 ZMODEM 协议关键流程:
- 接收文件名并创建本地文件;
- 解析并写入文件数据;
- 错误检测和自动请求重传;
- 传输终止与确认;
- 支持 ASCII、二进制等多种传输模式(默认使用 ZCBIN);
六、适用与移植建议
该程序适合作为以下用途:
- 在 PC 上调试串口文件传输功能;
- 嵌入式 Bootloader 文件接收功能的参考实现;
- 移植到 STM32、RT-Thread 等裸机/RTOS 系统中(需替换
FILE
接口为串口驱动); - 与上位机串口工具(如 XShell、SecureCRT)搭配使用,快速测试串口传输稳定性。
移植建议:
- 用平台串口驱动替代
fread/fputc
; - 用 Flash 或 FatFs 替代
fopen/fwrite
; - 精简数据缓存,控制内存占用;
- 加入超时处理和断电保护机制;
- 可选支持 YMODEM 做替代方案,结构更简单。
七、结语
本文通过对一份基于标准 C 的 ZMODEM 接收程序进行解析,展示了其实现机制与协议流程。作为串口文件传输的重要协议,ZMODEM 在嵌入式系统中具有重要价值,理解其底层工作原理有助于开发更加可靠和通用的通信方案。
如需实现嵌入式串口升级或远程配置功能,ZMODEM 是一个值得参考与实现的通信协议。