主要目的是用来熟悉go语言,通过该项目可以熟悉到的go知识点:
(1)go语言语法;
(2)go的goroutine使用方式;
(3)go通道chan的使用
(4)等待所有goroutine结束的同步信号使用;
(5)go的结构体定义和方法使用;
(1)支持批量上传下载文件,并进行md5值校验;
(2)支持查看文件列表;
(3)支持断点续传和下载文件;
(4)支持大文件切片上传和大文件切片下载;
(5)支持分片失败重传和失败重下载;
(6)支持控制每个文件上传和下载的最大goroutine数量;
(7)服务端根据配置文件读取保存文件目录、绑定IP和端口号信息等。
流程概述:
(1)上传文件时首先判断文件是否大于1M,如果小于1M则没必要进行分片,直接整个文件通过HTTP请求发送到Server端进行保存;
(2)如果文件大于1M,则首先判断该文件是不是上传了一部分的文件,这个通过查找当前目录下有没有对应元数据文件来判断,如果没有则是全新要上传的文件,否则是需要断点续传的文件;
(3)如果是全新要上传的文件,则会先对该文件进行计算,比如该文件能被切分成多个个分片,生成上传uuid,作为唯一上传标识,并把这些数据保存到本地文件(创建一个隐藏文件,后缀加上.uploading);
(4)同时还需向服务端先发送一个请求,让其先在保存目录创建一个uuid的目录,用来待会保存分片文件使用,同时服务端也会生成一个元数据文件;
(5)如果是需要断点续传的文件,则需要请求服务端获取该文件还缺少哪些文件分片没有上传(服务端只需从保存目录中已保存的序号结合文件元数据即可识别到哪些序号还没上传),并将这些切片序号发送回给客户端,假设有1,5,6,7,没发送,则服务端只需要发送1,5,-1即可标识,1分片和5到最后一个分片都没上传成功;
(6)在上传前会先启动一个goroutine,专门用来重传失败分片的,它会不断的从RetryChannel通道中读分片数据,如果没有则阻塞,如果有则重传该分片,如果再失败则再发送到通道中,可以看做当队列使用;
(7)开始读文件,如果是续传的,还可以根据续传情况进行偏移量偏移,跳过指定的切片段,读时每次只读1M,然后判断该切片是否已被上传过,如果上传过则无须再上传,可直接跳过,否则就创建一个goroutine进行异步上传;
(8)当所有goroutine都运行完成表示切片都上传完成了则发送请求告诉服务端切片已上传完成,服务端也会把文件状态置为active。
流程概述:实现思路跟上传相似,这里不再概述。
(1)文件分片
将大文件进行分片,定义分片规格为1M,比如有5M大小的文件,那么就会分成文件名为0,1,2,3,4,5这6个文件,上传到服务端后,服务端会创建一个uuid的文件夹用来保存这5个分片文件,并且会记录一个元数据文件,里面保存着该元数据文件对应哪个目录,文件切片大小、文件大小和文件md5等原信息。对于小于1M的普通文件则不进行切片处理,就是正常的一个文件,所以我程序里规定了文件名为.slice结尾的文件则为切片文件,否则为普通文件。
(2)断点续传和断点续载
首先是断点续传,在开始传文件时,我会创建一个隐藏文件作为上传元数据文件,比如文件名是file.txt,则我创建的元数据文件名为.file.txt.uploading,里面记录着文件元数据信息,比如上传UUID、文件大小和文件md5等信息,如果用户上传完成,则起最后会被删除掉,表示整个文件都上传完成了,假设上传过程中出现了中断,则下次重新上传该文件时我检测到该隐藏文件就知道它是还未上传完整的文件,会先去服务端请求看缺少哪些分片数据,比如该文件一共有1,2,3,4,5片,服务端响应回来说只收到了1,3,5片,那么待会我就只需要把0,2,4片重传一次即可。
断点续载同理,也是需要在客户端维护元数据,且通过查找已下载的分片来找出未下载的分片序号,然后只需要重新下载没有的分片即可。
(3)失败重传
上传器和下载器的结构体定义我都会定义一个RetryChannel,这是一个分片结构体类型的通道,当分片上传或下载失败时,会将分片发送到这个通道,在上传或下载开始时我都会启动一个goroutine,专门负责从这个通道读数据,读到了就对这个分片进行重新上传或下载。
(4)并发上传或下载
并发使用了go的goroutine,并发单位以文件切片为单位,同时通过通道(申请有数量限制的通道)的方式控制运行的goroutine的数量,同时采用go里的同步信号量来控制是否所有goroutine都运行完成了。
客户端目录结构:
上传器结构体定义:
// Uploader 上传器
type Uploader struct {
common.FileMetadata // 文件元数据
common.SliceSeq // 需要重传的序号
waitGoroutine sync.WaitGroup // 同步goroutine
NewLoader bool // 是否是新创建的上传器
FilePath string // 上传文件路径
SliceBytes int // 切片大小
RetryChannel chan *FilePart // 重传channel通道
MaxGtChannel chan struct{} // 限制上传的goroutine的数量通道
StartTime int64 // 上传开始时间
}
下载器结构体定义:
// Downloader 下载器
type Downloader struct {
common.FileMetadata // 文件元数据
common.SliceSeq // 需要重传的序号
waitGoroutine sync.WaitGroup // 同步goroutine
DownloadDir string // 下载文件保存目录
RetryChannel chan int // 重传channel通道
MaxGtChannel chan struct{} // 限制上传的goroutine的数量通道
StartTime int64 // 下载开始时间
}
服务端目录结构:
文件的传输采用的是HTTP协议,服务端的工作主要是起一个HTTP Server,然后监听对应URL,绑定对应的响应方法,同时把接收到的文件数据保存到指定目录下。
使用方法可用–help查看:
上传、列出和下载使用方法示例(图中的下载路径和文件路径可以自行修改,且确保服务端FtpServer目录下的etc目录下的config.json文件里指定的StoreDir指定目录存在):
服务端先启动:进入项目目录,执行:go run main.go
上传文件示例:
客户端运行:
服务端响应:
列出文件列表示例:
下载文件示例:
当然,这个小项目可改进点还有很多,我这里列出几个我想到的:
(1)需重传的序号计算算法还可以实现的更好点,比如还没传的,可以用1-3,5-9这样来表示;
(2)当前的md5计算是计算整个文件的,但其实可以给每个分片都赋予一个md5,这样就不用再最后累计一边整个文件的md5,降低读IO次数;
(3)下载文件时,其实可以开辟一个指定size的空洞文件,然后接收到文件分片可以按照偏移量写到给新文件中,避免了最后一步的合并过程的IO。
Client端项目github地址:https://github.com/luohaixiannz/FtpClient
Server端项目github地址:https://github.com/luohaixiannz/FtpServer
原网址: 访问
创建于: 2022-09-13 15:43:27
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
java windows火焰图_mob64ca12ec8020的技术博客_51CTO博客 - 在windows下不可行,不知道作者是怎样搞的 监听SpringBoot 服务启动成功事件并打印信息_监听springboot启动完毕-CSDN博客 SpringBoot中就绪探针和存活探针_management.endpoint.health.probes.enabled-CSDN博客 u2u转换板 - 嘉立创EDA开源硬件平台 Spring Boot 项目的轻量级 HTTP 客户端 retrofit 框架,快来试试它!_Java精选-CSDN博客 手把手教你打造一套最牛的知识笔记管理系统! - 知乎 - 想法有重合-理论可参考 安宇雨 闲鱼 机械键盘 客制化 开贴记录 文本 linux 使用find命令查找包含某字符串的文件_beijihukk的博客-CSDN博客_find 查找字符串 ---- mac 也适用 安宇雨 打字音 记录集合 B站 bilibili 自行搭建 开坑 真正的客制化 安宇雨 黑苹果开坑 查找工具包maven pom 引用地 工具网站 Dantelis 介绍的玩轴入坑攻略 --- 关于轴的一些说法 --- 非官方 ---- 心得而已 --- 长期开坑更新 [本人问题][新开坑位]关于自动化测试的工具与平台应用 机械键盘 开团 网站记录 -- 能做一个收集的程序就好了 不过现在没时间 -- 信息大多是在群里发的 - 你要让垃圾佬 都去一个地方看难度也是很大的 精神支柱 [超级前台]sprinbboot maven superdesk-app 记录 [信息有用] [环境准备] [基本完成] [sebp/elk] 给已创建的Docker容器增加新的端口映射 - qq_30599553的博客 - CSDN博客 [正在研究] Elasticsearch, Logstash, Kibana (ELK) Docker image documentation elasticsearch centos 安装记录 及 启动手记 正式服务器 39 elasticsearch 问题合集 不断更新 6.1.1 | 6.5.1 两个版本 博客程序 - 测试 - bug记录 等等问题 laravel的启动过程解析 - lpfuture - 博客园 OAuth2 Server PHP 用 Laravel 搭建带 OAuth2 验证的 RESTful 服务 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区 利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法 - 煮茶的博客 - SegmentFault 思否 使用 OAuth2-Server-php 搭建 OAuth2 Server - 午时的海 - 博客园 基于PHP构建OAuth 2.0 服务端 认证平台 - Endv - 博客园 Laravel 的 Artisan 命令行工具 Laravel 的文件系统和云存储功能集成 浅谈Chromium中的设计模式--终--Observer模式 浅谈Chromium中的设计模式--二--pre/post和Delegate模式 浅谈Chromium中的设计模式--一--Chromium中模块分层和进程模型 DeepMind 4 Hacking Yourself README.md update 20211011
Laravel China 简书 知乎 博客园 CSDN博客 开源中国 Go Further Ryan是菜鸟 | LNMP技术栈笔记 云栖社区-阿里云 Netflix技术博客 Techie Delight Linkedin技术博客 Dropbox技术博客 Facebook技术博客 淘宝中间件团队 美团技术博客 360技术博客 古巷博客 - 一个专注于分享的不正常博客 软件测试知识传播 - 测试窝 有赞技术团队 阮一峰 语雀 静觅丨崔庆才的个人博客 软件测试从业者综合能力提升 - isTester IBM Java 开发 使用开放 Java 生态系统开发现代应用程序 pengdai 一个强大的博主 HTML5资源教程 | 分享HTML5开发资源和开发教程 蘑菇博客 - 专注于技术分享的博客平台 个人博客-leapMie 流星007 CSDN博客 - 舍其小伙伴 稀土掘金 Go 技术论坛 | Golang / Go 语言中国知识社区
最新评论