# UDPDownloader **Repository Path**: hwalkingman/udpdownloader ## Basic Information - **Project Name**: UDPDownloader - **Description**: 基于UDP的文件下载器 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-05-18 - **Last Updated**: 2023-10-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # UDP Downloader ## 一、赛题 有一些数据文件(**百兆级**)需要通过网络分发给不同的客户。 设计开发一个数据下载功能,由 server 和 client 组成。 client 使用 **TCP 协议**发起与 server 沟通,**查询**并**选择**需要的数据; server 将待下载的数据通过 **UDP** 发送给 client。 ## 二、要求 1. 数据发送速度可根据网络**带宽自动调节** 2. client 完成数据接收之后需对比**完整性** 3. server 端支持同时对**多个客户**服务 4. 自定 server 与 client 之间的查询**通讯协议** ## 三、提交内容 建议使用 word 文档形式给出设计方案,内容可包括技术选型,实现思路,流程图,甚至伪代码以及界面原型等。 ## 四、技术难点 1. 基于 UDP 的文件下载协议 2. 带宽自动调节 1. UDP 不支持拥塞控制和重传机制,需要手动通过动态调整 UDP 数据包的大小和发送间隔 3. 大文件发送 1. 数据包的最大长度限制:UDP 协议规定每个数据包的最大长度为 64KB 4. 多个客户端服务 5. 完整性验证 ## 五、处理流程: ### 5.1 准备阶段 #### 服务端 1. 导入配置文件 2. 扫描下载文件的根目录,创建文件目录映像 3. 开启**TCP server 线程**,等待连接 4. 每有一个连接接入都会开启一个新的**后端业务线程**处理,使用线程池管理 #### 客户端 1. 初步渲染页面 2. 点击`"配置"按钮`,设置客户端配置(目标服务器[ip:TCP port],本机[ip:UDP port]) 3. 点击`"连接检查"按钮`,客户端后向服务端**TCP server**建立连接,测试是否能链接上(即执行==测试链接业务流程==) 1. 若可以链接,enable`"查询"按钮`。 2. 若不可链接,在控制台显示错误 4. 点击`"查询"按钮`,执行==查询业务流程==,获得文件目录结构`IndexTreeNode`,并渲染在`TreeView`上 5. 点击`TreeView`上,对应的文件,弹出路径选择框,选择要下载到的文件夹,之后执行==下载业务流程== > 实际业务中, 为节约连接资源, 查询请求采用短连接,下载请求采用长连接(只有当一个文件被完整下载后,占用的连接资源才会释放) > 在每一个**后端业务线程**中都按照 WelcomeMsg, XXXRequest-XXXReply, GoodbyeMsg 按顺序处理客户端请求。 ### 5.2 业务流程 1. 客户端向服务端测试TCP链接 1. **客户端**主动建立TCP socket连接,并短暂开启UDP server 2. 链接建立后,**服务端**使用TCP发送`WelcomeMsg` 3. **客户端**接收后,发送`TestUDPRequest`(包含客户端[ip:UDP port]),并短暂开启UDP server,并等待10s 4. **服务端**接收后,使用UDP发送同一份`WelcomeMsg` 5. **客户端**, 1. 若10s内收到信息,则发送`TestUDPReply`(包含成功信息) 2. 反之,送`TestUDPReply`(包含失败信息) 6. **客户端**再次发送`GoodbyeMsg` 7. **服务端**接收后,主动断开链接 2. 客户端向服务端请求文件目录 $\times N$ 1. **客户端**主动建立TCP socket连接 2. 链接建立后,**服务端**发送`WelcomeMsg` 3. **客户端**接收后,发送`QueryRequest`(包含相对绝对路径与md5值) 4. **服务端**接收后,查询`IndexManager`获取目录下文件信息,并通过`QueryReply`的方式封装返回 5. **客户端**接收后,发送`GoodbyeMsg` 6. **服务端**接收后,主动断开链接 3. 客户端向服务端下载某一文件 1. **客户端**主动建立TCP socket连接 2. 链接建立后,**服务端**发送`WelcomeMsg` 3. **客户端**接收后,发送`DownloadRequest`,其中包含下载的文件路径,文件MD5,以及自己的可访问ip和开放的UDP端口 4. **服务端**接收后, 1. 如果路径不存在或MD5不一致,则返回`DownloaderReply`包含错误信息,要求服务端刷新路径后,重新下载。 2. 如果路径存在,则为该文件创建Reader, 返回`DownloaderReply`,其中包含文件源信息及batchSize,==计算分块数量根据固定大小进行分块==(计算过程也可以提前至文件准备阶段) (本次通信同时承担网络带宽检测的功能) 5. **客户端**接收后, 1. 对于4.1 关闭UDP server,并发送`GoodbyeMsg`,以结束通信 2. 对于4.2 准备`FileManager`并选定下载位置开始下载 6. **服务端**根据网络带宽,按照一定时间间隔发送`UDPPackage`,其中包含二进制文件信息,文件块序列号与块校验码,间隔发送过程使用`ScheduledExecutor`实现 7. **客户端**根据batchSize大小设定数组接收并存储对应位置的信息 8. 当达到batchSize时,**服务端**向**客户端**发送`CheckRequest`,**客户端**需要校验全部包已经收到,并返回`CheckReply` 1. 若全部收到,`CheckReply`附带成功校验码,随后将块按顺序存储到硬盘中 2. 若缺失包,`CheckReply`附带不全校验码以及缺失内容序号 (本次通信同时承担网络带宽检测的功能) 9. **服务端**接收到`CheckReply`后, 1. 对于8.1,重复6-8,直至全部内容发送 2. 对于8.2,重发缺失包,直至8.1 10. 内容全部发送后,**服务端**发送`FinalCheckMsg`,客户端存储全部数据到文件,并计算文件MD5,一致则返回`GoodbyeMsg`,否则删除文件并报错。 11. **服务端**接收后,主动断开链接 ## 六、文件结构 ```text UDPDownloader ├─ java │ ├─ client │ │ ├─ FileClient.java # 客户端业务 │ ├─ filemgr │ │ ├─ FileManager.java # 用于从磁盘中读取/写入文件块 │ │ ├─ IndexManager.java # 用于管理可下载目录的索引信息 │ ├─ gui # 用户界面 │ ├─ message # 服务端与客户端通信数据包 │ │ ├─ annotation # 用于JSON序列化注解 │ │ ├─ exception # 序列化异常 │ │ ├─ UDPPackage.java # 下载时发送的 UDP 文件数据包 │ │ ├─ ... │ │ └─ WelcomeMsg.java # 初次连接,服务端发送的欢迎消息 │ ├─ server │ │ ├─ CommunicationTask.java # 每个连接的处理流程 │ │ ├─ DownloaderTask.java # 文件下载处理流程 │ │ └─ FileServer.java # 服务端业务 │ ├─ ServerStarter.java # 服务端启动器 │ └─ UDPDownloaderApplication.java # 客户端启动器 ├─ resources │ ├─ server-setting.yaml # 服务端配置文件 │ └─ client-view.fxml # 客户端界面UI ├── readme.md └── pom.xml ``` ## something Apache JMeter是一个开源的、功能强大的性能测试工具 能否对用一个文件打开两个不同的read流[**可以**] ## Contributors - HKun_y