421 lines
16 KiB
Markdown
421 lines
16 KiB
Markdown
# 数据传输问题
|
||
|
||
<cite>
|
||
**本文引用的文件**
|
||
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp)
|
||
- [Zmodem.h](file://h/Zmodem.h)
|
||
- [FileTransfer.h](file://h/FileTransfer.h)
|
||
- [HttpDownload.cpp](file://cpp/Tools/HttpDownload.cpp)
|
||
- [HttpDownload.h](file://h/HttpDownload.h)
|
||
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp)
|
||
- [http_client.h](file://h/httpClient/http_client.h)
|
||
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
|
||
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [引言](#引言)
|
||
2. [项目结构](#项目结构)
|
||
3. [核心组件](#核心组件)
|
||
4. [架构总览](#架构总览)
|
||
5. [详细组件分析](#详细组件分析)
|
||
6. [依赖关系分析](#依赖关系分析)
|
||
7. [性能考量](#性能考量)
|
||
8. [故障排查指南](#故障排查指南)
|
||
9. [结论](#结论)
|
||
10. [附录](#附录)
|
||
|
||
## 引言
|
||
本文件聚焦于Geomative Studio工程中的数据传输问题与实现细节,围绕以下目标展开:
|
||
- 阐述Zmodem协议传输失败的常见原因与处理策略
|
||
- 解释HTTP下载超时、断点续传失败等常见问题及修复思路
|
||
- 基于FileTransfer.cpp与Zmodem.cpp,说明Zmodem工作机制与关键参数配置
|
||
- 分析HttpDownload.cpp中curl_perform失败的处理逻辑,并结合http_client.h中的异常传播路径
|
||
- 提供性能优化建议:超时设置、压缩传输、协议选择等
|
||
- 列举常见错误场景与重试策略,覆盖大文件传输中断、断点续传失败等
|
||
|
||
## 项目结构
|
||
本项目涉及两类主要传输通道:
|
||
- 串口Zmodem文件传输:通过Zmodem类实现RS232串口上的可靠文件传输
|
||
- HTTP下载:包含自研基于套接字的多线程下载器与基于libcurl的下载器
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "串口传输"
|
||
FT["FileTransfer.h"]
|
||
ZH["Zmodem.h"]
|
||
ZC["Zmodem.cpp"]
|
||
CRC16["Crc16.cpp"]
|
||
CRC32["Crc32.cpp"]
|
||
end
|
||
subgraph "HTTP下载"
|
||
HDH["HttpDownload.h"]
|
||
HDC["HttpDownload.cpp"]
|
||
CRL["FileTransfer_crul.cpp"]
|
||
HCH["http_client.h"]
|
||
end
|
||
FT --> ZH --> ZC
|
||
ZC --> CRC16
|
||
ZC --> CRC32
|
||
HDH --> HDC
|
||
CRL --> HCH
|
||
```
|
||
|
||
图表来源
|
||
- [FileTransfer.h](file://h/FileTransfer.h#L1-L49)
|
||
- [Zmodem.h](file://h/Zmodem.h#L1-L143)
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L1-L200)
|
||
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp#L1-L54)
|
||
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp#L1-L51)
|
||
- [HttpDownload.h](file://h/HttpDownload.h#L1-L155)
|
||
- [HttpDownload.cpp](file://cpp/Tools/HttpDownload.cpp#L1-L200)
|
||
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L1-L120)
|
||
- [http_client.h](file://h/httpClient/http_client.h#L1-L120)
|
||
|
||
章节来源
|
||
- [FileTransfer.h](file://h/FileTransfer.h#L1-L49)
|
||
- [Zmodem.h](file://h/Zmodem.h#L1-L143)
|
||
- [HttpDownload.h](file://h/HttpDownload.h#L1-L155)
|
||
|
||
## 核心组件
|
||
- FileTransfer抽象基类:定义了通用的发送/接收接口,派生出Zmodem具体实现
|
||
- Zmodem类:实现Zmodem协议的发送/接收流程,含帧类型、CRC校验、超时控制、断点续传等
|
||
- HttpDownload类:基于套接字的多线程HTTP下载器,支持断点续传与进度管理
|
||
- FileTransfer_crul类:基于libcurl的下载器,支持超时、进度回调、错误缓冲
|
||
- http_client.h:基于WinHttp的异步HTTP客户端,包含异常类型与错误传播路径
|
||
|
||
章节来源
|
||
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp#L1-L47)
|
||
- [FileTransfer.h](file://h/FileTransfer.h#L1-L49)
|
||
- [Zmodem.h](file://h/Zmodem.h#L1-L143)
|
||
- [HttpDownload.h](file://h/HttpDownload.h#L1-L155)
|
||
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L1-L120)
|
||
- [http_client.h](file://h/httpClient/http_client.h#L1-L120)
|
||
|
||
## 架构总览
|
||
下面的序列图展示了三种典型数据传输路径及其错误处理要点:
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant App as "应用层"
|
||
participant Z as "Zmodem"
|
||
participant Port as "串口设备"
|
||
participant C16 as "CRC16"
|
||
participant C32 as "CRC32"
|
||
App->>Z : "开始发送文件"
|
||
Z->>Port : "发送ZFILE帧"
|
||
Port-->>Z : "接收ZFILE确认"
|
||
loop "发送文件内容"
|
||
Z->>Port : "发送ZDATA帧(带CRC)"
|
||
Port-->>Z : "返回ZACK/ZRPOS/ZSKIP"
|
||
alt "ZACK"
|
||
Z->>Z : "更新传输位置"
|
||
else "ZRPOS"
|
||
Z->>Port : "重定位到指定位置"
|
||
else "ZSKIP"
|
||
Z-->>App : "跳过文件"
|
||
end
|
||
end
|
||
Z->>Port : "发送ZEOF/ZFIN"
|
||
Port-->>Z : "确认完成"
|
||
Z-->>App : "返回结果"
|
||
Note over Z,C16,C32 : "CRC16/CRC32用于帧与数据校验"
|
||
```
|
||
|
||
图表来源
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L150-L380)
|
||
- [Zmodem.h](file://h/Zmodem.h#L1-L143)
|
||
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp#L1-L54)
|
||
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp#L1-L51)
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant App as "应用层"
|
||
participant HD as "HttpDownload"
|
||
participant Sock as "套接字"
|
||
participant Srv as "HTTP服务器"
|
||
App->>HD : "StartHttpTask(任务)"
|
||
HD->>Sock : "Connect/发送HEAD/GET"
|
||
Sock-->>HD : "响应头(状态码/长度/重定向)"
|
||
alt "支持断点续传"
|
||
HD->>Sock : "Range : bytes=起止-"
|
||
Sock-->>HD : "206 Partial Content"
|
||
HD->>HD : "创建分段任务/写入配置"
|
||
else "不支持续传"
|
||
HD->>HD : "回退单线程/禁用续传"
|
||
end
|
||
par "多线程下载"
|
||
HD->>Sock : "并发Range请求"
|
||
Sock-->>HD : "分块数据"
|
||
HD->>HD : "合并写入/更新进度"
|
||
end
|
||
HD-->>App : "完成/失败"
|
||
```
|
||
|
||
图表来源
|
||
- [HttpDownload.cpp](file://cpp/Tools/HttpDownload.cpp#L60-L220)
|
||
- [HttpDownload.h](file://h/HttpDownload.h#L1-L155)
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant App as "应用层"
|
||
participant C as "FileTransfer_crul"
|
||
participant Curl as "libcurl"
|
||
participant Srv as "HTTP服务器"
|
||
App->>C : "DownloadFile()"
|
||
C->>Curl : "curl_easy_init/设置选项"
|
||
C->>Curl : "curl_easy_perform()"
|
||
alt "执行成功"
|
||
Curl-->>C : "返回CURLE_OK"
|
||
C-->>App : "写入文件/返回成功"
|
||
else "执行失败"
|
||
Curl-->>C : "返回错误码/错误缓冲"
|
||
C->>C : "记录日志/提示用户"
|
||
C-->>App : "返回失败"
|
||
end
|
||
```
|
||
|
||
图表来源
|
||
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L150-L280)
|
||
- [http_client.h](file://h/httpClient/http_client.h#L1-L120)
|
||
|
||
## 详细组件分析
|
||
|
||
### Zmodem协议传输问题与处理
|
||
- 关键帧类型与行为
|
||
- ZFILE:发送文件名与元数据;接收方需确认后进入ZDATA阶段
|
||
- ZDATA:携带文件数据,支持多种帧尾标志(ZCRCE/ZCRCG/ZCRCQ/ZCRCW),用于不同ACK策略
|
||
- ZEOF/ZFIN:文件结束与会话结束
|
||
- ZRPOS:接收方要求发送方重定位到指定偏移
|
||
- ZSKIP/ZCAN/ZABORT:跳过/取消/中止
|
||
- 超时与重试
|
||
- 读取字符与头部时使用超时参数,超时返回TIMEOUT,触发错误计数或终止
|
||
- 对于TIMEOUT/错误计数超过阈值,返回ZERROR并终止当前文件或会话
|
||
- 断点续传
|
||
- 接收方通过发送ZPOS并携带期望位置,若发送方返回ZRPOS则重定位到该位置继续
|
||
- 发送方在收到ZRPOS时,重置传输位置并继续发送
|
||
- CRC校验
|
||
- 发送与接收均使用CRC16/CRC32进行帧头与数据校验,校验失败返回错误并重发
|
||
- 常见失败场景
|
||
- 串口缓冲溢出/握手信号干扰(XON/XOFF),导致读取阻塞或丢帧
|
||
- 接收方未及时ACK,发送方超时重发,最终因累计错误而失败
|
||
- 文件系统写入失败或磁盘空间不足
|
||
- 通信波特率/奇偶校验不匹配导致解码错误
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start(["开始发送文件"]) --> SendZFILE["发送ZFILE帧"]
|
||
SendZFILE --> WaitZACK{"收到ZACK/确认?"}
|
||
WaitZACK --> |否| Retry["重发ZFILE/等待"]
|
||
Retry --> Timeout{"超时?"}
|
||
Timeout --> |是| Fail["返回ZERROR/失败"]
|
||
Timeout --> |否| WaitZACK
|
||
WaitZACK --> |是| Loop["循环发送ZDATA帧"]
|
||
Loop --> ACK{"收到ZACK?"}
|
||
ACK --> |是| UpdatePos["更新传输位置"]
|
||
ACK --> |否| ZRPOS{"收到ZRPOS?"}
|
||
ZRPOS --> |是| Seek["重定位到指定偏移"]
|
||
ZRPOS --> |否| Skip{"收到ZSKIP?"}
|
||
Skip --> |是| NextFile["跳过文件/下一个"]
|
||
Skip --> |否| Fail
|
||
UpdatePos --> Loop
|
||
Loop --> EOF["发送ZEOF/ZFIN"]
|
||
EOF --> Done(["完成"])
|
||
```
|
||
|
||
图表来源
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L150-L380)
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L504-L551)
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L1717-L1746)
|
||
|
||
章节来源
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L132-L170)
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L170-L220)
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L262-L378)
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L504-L551)
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L558-L779)
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L898-L960)
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L1717-L1746)
|
||
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp#L1-L54)
|
||
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp#L1-L51)
|
||
|
||
### HTTP下载超时与断点续传失败
|
||
- 超时与重定向处理
|
||
- 发送请求后解析响应头,提取状态码、内容长度、最后修改时间
|
||
- 对于3xx重定向,解析Location并更新URL;4xx客户端错误直接失败;5xx服务器错误可重试
|
||
- 使用Range请求探测服务器是否支持断点续传,若返回206则启用分段下载
|
||
- 断点续传机制
|
||
- 首次下载创建“.chr”占位文件,按线程数划分区间,写入配置文件
|
||
- 续传时读取配置文件,比较文件大小一致性,决定是否继续
|
||
- 下载完成后合并分段并清理临时文件
|
||
- 常见失败场景
|
||
- 网络不稳定导致部分线程超时或连接中断
|
||
- 服务器不支持Range导致无法断点续传,回退单线程
|
||
- 写入磁盘失败或权限不足
|
||
- DNS解析失败或IPV4限制导致连接失败
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
S(["开始下载"]) --> Head["发送HEAD请求获取长度/状态"]
|
||
Head --> Resp{"状态码/长度有效?"}
|
||
Resp --> |否| Fail["失败/重试(5xx)"]
|
||
Resp --> |是| Resume{"支持断点续传?"}
|
||
Resume --> |是| Split["按线程划分区间/写配置"]
|
||
Resume --> |否| Single["单线程下载/禁用续传"]
|
||
Split --> Multi["多线程并发Range请求"]
|
||
Single --> Write["顺序写入"]
|
||
Multi --> Merge["合并分段/更新进度"]
|
||
Merge --> Done(["完成"])
|
||
Write --> Done
|
||
```
|
||
|
||
图表来源
|
||
- [HttpDownload.cpp](file://cpp/Tools/HttpDownload.cpp#L417-L518)
|
||
- [HttpDownload.cpp](file://cpp/Tools/HttpDownload.cpp#L520-L663)
|
||
- [HttpDownload.cpp](file://cpp/Tools/HttpDownload.cpp#L667-L718)
|
||
- [HttpDownload.cpp](file://cpp/Tools/HttpDownload.cpp#L720-L800)
|
||
- [HttpDownload.h](file://h/HttpDownload.h#L1-L155)
|
||
|
||
章节来源
|
||
- [HttpDownload.cpp](file://cpp/Tools/HttpDownload.cpp#L60-L220)
|
||
- [HttpDownload.cpp](file://cpp/Tools/HttpDownload.cpp#L220-L420)
|
||
- [HttpDownload.cpp](file://cpp/Tools/HttpDownload.cpp#L420-L800)
|
||
- [HttpDownload.h](file://h/HttpDownload.h#L1-L155)
|
||
|
||
### libcurl下载器的错误传播与处理
|
||
- curl_easy_perform失败处理
|
||
- 执行失败时记录错误码与错误缓冲信息,弹窗提示用户检查网络
|
||
- 对“写入文件失败”或“写入字节数不匹配”进行日志记录与返回
|
||
- 支持设置超时、进度回调、错误缓冲、IPV4解析等选项
|
||
- 重试策略
|
||
- URL可达性测试采用短超时与多次重试,提升弱网环境下的成功率
|
||
- 与http_client.h的关系
|
||
- http_client.h提供基于WinHttp的异步HTTP客户端,包含异常类型与错误传播路径
|
||
- 两者分别面向不同场景:libcurl更灵活,WinHttp异步回调更复杂但可控
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant App as "应用层"
|
||
participant C as "FileTransfer_crul"
|
||
participant Curl as "libcurl"
|
||
participant FS as "文件系统"
|
||
App->>C : "DownloadFile()"
|
||
C->>Curl : "设置URL/超时/回调/错误缓冲"
|
||
C->>Curl : "curl_easy_perform()"
|
||
alt "成功"
|
||
Curl-->>C : "CURLE_OK"
|
||
C->>FS : "写入文件"
|
||
C-->>App : "返回成功"
|
||
else "失败"
|
||
Curl-->>C : "错误码/错误缓冲"
|
||
C->>C : "记录日志/提示用户"
|
||
C-->>App : "返回失败"
|
||
end
|
||
```
|
||
|
||
图表来源
|
||
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L150-L280)
|
||
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L280-L350)
|
||
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L350-L428)
|
||
- [http_client.h](file://h/httpClient/http_client.h#L1-L120)
|
||
|
||
章节来源
|
||
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L150-L280)
|
||
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L350-L428)
|
||
- [http_client.h](file://h/httpClient/http_client.h#L1-L120)
|
||
|
||
## 依赖关系分析
|
||
- Zmodem依赖FileTransfer抽象接口,CRC16/CRC32用于帧与数据校验
|
||
- HttpDownload依赖套接字与线程模型,配合配置文件实现断点续传
|
||
- FileTransfer_crul依赖libcurl,提供简单易用的下载接口
|
||
- http_client.h提供WinHttp异步客户端,适合需要精细错误处理与回调的场景
|
||
|
||
```mermaid
|
||
graph LR
|
||
FT["FileTransfer.h"] --> ZH["Zmodem.h"]
|
||
ZH --> ZC["Zmodem.cpp"]
|
||
ZC --> CRC16["Crc16.cpp"]
|
||
ZC --> CRC32["Crc32.cpp"]
|
||
HDH["HttpDownload.h"] --> HDC["HttpDownload.cpp"]
|
||
CRL["FileTransfer_crul.cpp"] --> HCH["http_client.h"]
|
||
```
|
||
|
||
图表来源
|
||
- [FileTransfer.h](file://h/FileTransfer.h#L1-L49)
|
||
- [Zmodem.h](file://h/Zmodem.h#L1-L143)
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L1-L200)
|
||
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp#L1-L54)
|
||
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp#L1-L51)
|
||
- [HttpDownload.h](file://h/HttpDownload.h#L1-L155)
|
||
- [HttpDownload.cpp](file://cpp/Tools/HttpDownload.cpp#L1-L200)
|
||
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L1-L120)
|
||
- [http_client.h](file://h/httpClient/http_client.h#L1-L120)
|
||
|
||
章节来源
|
||
- [FileTransfer.h](file://h/FileTransfer.h#L1-L49)
|
||
- [Zmodem.h](file://h/Zmodem.h#L1-L143)
|
||
- [HttpDownload.h](file://h/HttpDownload.h#L1-L155)
|
||
|
||
## 性能考量
|
||
- 超时设置
|
||
- Zmodem:读取字符/头部超时约10秒量级,可根据波特率动态调整
|
||
- HttpDownload:HEAD请求短超时快速探测,GET请求长超时保证稳定
|
||
- FileTransfer_crul:默认超时较长,可在弱网环境下适当缩短
|
||
- 压缩传输
|
||
- HTTP侧可协商Accept-Encoding,服务端返回压缩内容时减少带宽占用
|
||
- Zmodem本身不提供压缩,可通过上层协议或外部工具实现
|
||
- 协议选择
|
||
- 高速、稳定网络:优先使用HTTP多线程下载
|
||
- 低速、高误码串口:优先使用Zmodem,配合CRC32与断点续传
|
||
- 并发与缓冲
|
||
- HttpDownload的多线程分段下载可显著提升吞吐,注意磁盘写入与网络拥塞
|
||
- Zmodem的接收缓冲区大小影响吞吐与延迟,需平衡内存与性能
|
||
|
||
[本节为通用指导,无需特定文件引用]
|
||
|
||
## 故障排查指南
|
||
- Zmodem传输失败
|
||
- 现象:TIMEOUT频繁、ZRPOS重定位失败、CRC校验失败
|
||
- 排查:检查串口参数(波特率/奇偶/停止位)、握手信号、线缆质量
|
||
- 处理:增大超时、降低帧大小、启用断点续传、重发失败段
|
||
- HTTP下载超时
|
||
- 现象:HEAD/GET超时、状态码非200、服务器不支持Range
|
||
- 排查:DNS解析、代理设置、防火墙、服务器限速
|
||
- 处理:缩短超时、增加重试次数、回退单线程、切换IPV4
|
||
- 文件完整性校验错误
|
||
- 现象:CRC校验失败、写入字节数不匹配
|
||
- 排查:磁盘空间、文件权限、写入缓冲区
|
||
- 处理:重试写入、检查磁盘健康、启用断点续传
|
||
- curl_perform失败
|
||
- 现象:返回错误码、错误缓冲有内容
|
||
- 排查:网络环境、证书验证、URL有效性
|
||
- 处理:打印错误缓冲、提示用户检查网络、必要时禁用SSL验证(仅测试)
|
||
|
||
章节来源
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L898-L960)
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L1240-L1267)
|
||
- [HttpDownload.cpp](file://cpp/Tools/HttpDownload.cpp#L417-L518)
|
||
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L240-L280)
|
||
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L350-L428)
|
||
|
||
## 结论
|
||
- Zmodem协议通过严格的帧类型、CRC校验与断点续传来保障串口传输的可靠性,适用于弱网络与高误码场景
|
||
- HTTP下载器提供了灵活的断点续传与多线程能力,适合稳定网络环境下的大文件传输
|
||
- libcurl与WinHttp分别满足不同需求:前者简单易用,后者提供细粒度的异步回调与错误处理
|
||
- 面向生产环境,建议结合超时策略、重试机制与日志记录,持续优化传输稳定性与性能
|
||
|
||
[本节为总结,无需特定文件引用]
|
||
|
||
## 附录
|
||
- 关键参数与配置
|
||
- Zmodem:接收缓冲区大小、帧尾策略、CRC类型选择、超时阈值
|
||
- HttpDownload:线程数、分段区间、配置文件路径、写入缓冲
|
||
- FileTransfer_crul:超时、进度回调、错误缓冲、IPV4解析
|
||
- 常见错误码参考
|
||
- libcurl错误码范围与含义可参考curl.h中的枚举定义
|
||
|
||
章节来源
|
||
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L1-L120)
|
||
- [HttpDownload.cpp](file://cpp/Tools/HttpDownload.cpp#L1-L200)
|
||
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L1-L200) |