# AFTS **Repository Path**: kioz-wang/afts ## Basic Information - **Project Name**: AFTS - **Description**: File Transfer Tool—— 基于 OpenSSL 的文件传输工具 - **Primary Language**: C - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2020-11-04 - **Last Updated**: 2025-08-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Advanced File Tranfer System --- ## Get Start > 环境要求: > > - Ubuntu 20.04 LTS > - packages: git make gcc openssl libssl1.1 libssl-dev 1. 使用 `git clone` 获取源码; ```sh git clone https://gitee.com/charz/afts ``` 在项目目录下执行 `./startup.sh` 并选择 **Generate Demo** 以立即开始体验,或继续按照以下步骤构建 demo。 2. 编译项目: ```sh cd afts mkdir obj bin make # 可执行文件被放在 bin 目录里 make clean # 删除所有的目标文件 ``` 3. 使用 `openssl` 命令生成公私钥; ```sh # 生成 2048 bit 长的 RSA 私钥 # 该私钥中亦包含有公钥信息,故可从中提取出公钥 openssl genrsa -out afts.key ``` 4. 使用 `openssl` 命令生成证书请求; ```sh openssl req -new -key afts.key -out afts.csr # openssl 将询问几个信息,用以生成证书请求 # 如果不想回答,可键入'.'后回车,对于必需的信息,openssl 将使用默认值填写 ``` 5. 使用安全的方式将证书请求发送给 CA,并等待接收由 CA 颁发的证书; 对于小团队之间的通信,不需要花费一大笔钱,辗转从专业的 CA 机构获取证书,我们也可以利用 openssl 自己给自己签发证书。 ```sh mkdir minca; cd minca openssl genrsa -out ca.key # 生成 CA 的公私钥 openssl req -x509 -key ca.key -out ca.crt # 生成 CA 的自签根证书 # 收到证书请求 afts.csr openssl x509 -req -in afts.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out afts.crt # 将 afts.crt 送回请求方 ``` 6. 至此,得到满足程序基本运行的所有文件。 ```txt afts.key afts.crt afts ca.crt ``` 7. 将目录组织成如下结构,即可开始体验 afts。 ```txt . ├── afts └── .hi ├── afts.crt ├── afts.key └── ca.crt 1 directory, 4 files ``` --- ## Usage ### Non-interactive Mode Enter `afts -h` to get a brief help. Following are more details: ```txt Usage: afts -c -w|r fname -a ip:port afts -s [-p port] afts -i -a ip:port [-p port] afts -h ``` `-c` 为单次任务客户端模式,`-s`为服务端模式,`-i`为多任务交互式模式。 ### Interactive Mode 如果没有通过 `-p` 提供监听端口,程序将进行询问,如果不想启动后台服务端,那么根据提示键入`.`即可。而后,即进入交互模式。此时,本地客户端已与远程服务端建立连接(,本地服务端正在指定端口监听连接请求),程序将打印出`Enter > `以等待输入。 输入有 4 种类型: 1. `: cmd` 2. `w filename` 3. `r filename` 4. `p TskID` `:` 发送命令到远程服务端,而后服务端将返回一个 TEXT 包,以文本的形式返回执行结果; 总计 15 个命令,目前支持的命令有 ```txt exit,ls,tree ``` `w`,`r` 上传、下载文件,将创建一线程进行文件传输(即后台传输),同时在提示消息中给出此次传输任务的 ID。 `p` 查看对应文件传输任务的进度,这将阻塞式地显示一进度条,此时敲击任何键将回到交互模式。如果在`TskID`后紧跟着一个`!`,则将暂停该任务。 当无法解析出有效的指令时,全部输入将作为文本发送到远程服务端。注意:‘文本’始终以 '\n''\0' 序列结尾。 --- ## Software Architecture ### 通信连接关系图 Diagram_connection --- ## Protocol ### PDU #### terminology writer: 文件或纯文本消息的发送方 reader: 文件或纯文本消息的接收方 send: 指一次发送(或写出)的行为,不限于 writer recv: 指一次接收(或读入)的行为,不限于 reader UP : 客户端做 writer 而服务端做 reader 的文件传输活动 DWON: 客户端做 reader 而服务端做 writer 的文件传输活动 TEXT: 客户端向服务端 send 纯文本或指令,对于后者,还要 recv 服务端的响应 #### overview 协议报文由头部(header)和正文(content)构成,其中头部固定为 14 字节长。 头部又分为主头部(main header)和头部拓展(extension),长度分别为 2 字节、12 字节。 PDU_overview #### header ##### main header 主头部由 2 比特的类型域(type),2 比特的状态域(status),1 比特的子类型域(subtype)或 4 比特的命令域(cmd),以及位于尾部暂未使用的 1 字节构成。 cmd 使用了 [0:3] 位,其中 0x1111(exit),0x0000(plain) 已被占用,用户可在剩下的空间内自定义命令。 > NOTXT 是一种特殊的 UP 或 DOWN 类型 PDU_mheader ##### extension 4-byte len,最大值为 232,即 4G。实际的网络环境中,一次性连续地传送 4G 的数据是不现实的,这里只是为了构成一个 4-byte 整型,方便程序的处理而已。当然也可以设计为 2-byte 短整型,但这样,又使得一次性最大可传送的数据容量过小了。 4-byte block idx 最大允许 232 块,10-bit piece idx 最大允许 210 片,2-byte size 限制片的大小最大为 216 字节,即 64KB,从而,块的大小最大为 64MB,总的可定位大小为 258 字节。 10-bit piece idx 占用了全部的 [14] 字节,以及 [15] 字节的 [0:1] 位。 8-byte fsize 用于传递文件的大小信息,大小超过 258 的协议包无效。 PDU_extension #### content 正文可能是这样几种情形:文本(text)、哈希值(hval)、文件名(fname)、文件内容(fcont),以及哈希值和文件名的组合(hval+fname)。 PDU_content ### Sequence Diagram 实现“断点续传”的关键在于,文件传输的读端,需要在程序主动或被动终止时,将当前传输的状态(或说进度)保存起来。当程序再次启动该文件传输时,读端首先尝试从本地保存的状态文件中获取到之前被中断时的状态,如果状态文件不存在,则对当前状态进行初始化。而写端不存在所谓状态文件。 在下面的时序中,文件的传输主要有三个阶段: 1. 客户端请求服务端 2. 服务端答复 3. 双方协商 4. 文件传输 5. 传输结束 在交互模式中,当客户端从输入中解析出文件传输任务时,首先检查任务的有效性,而后创建线程执行之。 在新的线程中,客户端会向服务端监听端口请求新的连接;从上面的通信连接关系图中可以看出,服务端监听端口在收到请求后,便会新建一线程以响应该请求并建立连接。随后客户端恢复或初始化状态,并正式进入**阶段1**,即向服务端发送请求报文。服务端线程收到请求后,检查请求的有效性,而后做出答复,即**阶段2**。当答复内容有“有效”时,传输活动便继续。 > 注意:当客户端为写端时,会在请求报文中包含文件内容的哈希值(在文件名之前),这样作为读端的服务端便可以决定是否要重置经恢复得到的状态信息。当客户端为读端时,文件内容的哈希将由服务端在服务端的“有效”答复中给出,从而客户端可决定是否要重新确定“分块分片”方案,以及是否要重置经恢复得到的状态信息。 接着双方进入**阶段3**,客户端、服务端,两者中,作为文件传输读端的一方将主动发送协商请求报文,即 “分块分片”方案由读端决定 ;另一方在收到报文后,将该报文原样发回,并进入**阶段4**。 > 注意:即使读端的状态是经恢复得到的,也同样要参与协商,因为写端需要从协商过程中获取到必要的信息,如“分块分片”的方案,以在下一阶段中,正确地响应内容请求报文。 读端在收到返回的报文后,亦进入**阶段4**。在该阶段中,读端始终首先发送内容请求报文,而后等待;写端则首先被动等待报文,并在收到报文后,发送要求的内容报文。 **阶段5**可在**阶段4**正常结束后到达,也可由文件传输活动的双方,主动发送结束报文中止**阶段4**后到达,亦有可能,从任何阶段因外部或内部异常到达。当读端经过非正常途径到达**阶段5**时,首先需要保存当前的有效的状态信息,而后与服务端同步退出。 > 注意:初始化后的状态信息,只有在经过一次成功的协商后,才变得有效。 #### Transfer Text 在交互模式中,通信双方可传输文本信息。 Diagram_transfertext #### Download File 客户端下载位于服务端的文件。 Diagram_downloadfile #### Read File 客户端将文件上传到服务端。 Diagram_uploadfile ---