1. 当前位置: 网站首页 >  路由器百科 >  断点续传是什么原理?下载断了接着下,我抓包看到Range和206这么配合

断点续传是什么原理?下载断了接着下,我抓包看到Range和206这么配合

断点续传原理图:Range请求切4段并行下载拼回原文件md5一致,206与416状态码对话

上个月帮表弟下飞牛的安装镜像,四个多G,下到97%他家跳闸了。来电之后他盯着下载器那个「继续」按钮问我:点这个是从头再来,还是从97%接着来?要是从头再来,那这软件显示的「已下载3.9G」是糊弄人的?

这事我以前也含糊。真抓包看了一遍才弄明白:断点续传不是下载器自己发明的魔法,是HTTP协议里一对早就写好的搭档——Range请求头和206状态码。今天把这对搭档拆开讲清楚,顺带说说多线程下载器为什么快。

先把三次「切块」掰开,别混成一团

聊断点续传容易跟另外两个「切块」搞混,先划清界限。

一个是网线层面的包分片。你家宽带MTU是1500,大包要在网络层拆散了传,那是路由器之间的事,跟下载器没关系,之前写过一篇MTU是什么意思专门讲它。

另一个是应用层自己切块。视频网站把一部片子切成几千个10秒的小文件,那是HLS的玩法,看视频为什么能随便拖进度条里数过,10分钟被切了64片。BT下载也自己按1MB一块切,每块带指纹校验,磁力链接拆开看的就是那套。这两家的「块」是真实存在的独立文件,一块一块单独下。

而HTTP断点续传不一样:服务器上就一个完整的文件,谁也没切它。是下载器在请求里开口说「我只要第几字节到第几字节」,服务器从同一个文件上现场剁一段给你。文件没变,变的是你要的方式。

Range是怎么开口要的,服务器怎么回话

我拿自家站上一张39050字节的图做了组实验,请求头里加一行Range,看服务器怎么接。

要前1024字节,写Range: bytes=0-1023。服务器回话第一句是206 Partial Content——注意不是200,200是「整个文件都给你」,206是「你要的那一段给你」。后面跟着一行Content-Range: bytes 0-1023/39050,斜杠前的0-1023是这次实际给的段,斜杠后的39050是全文总长。落地一看,正好1024字节,一分不多。

要尾巴也行,写Range: bytes=38026-,结尾不写,服务器自动补到文件末尾。回的还是206,Content-Range: bytes 38026-39049/39050,落地1024字节。这个「开头不写」的变体也有:bytes=-1024表示「最后1024字节」,下载器校验文件尾的时候爱用。

那要是个不存在的段呢?我故意要bytes=99999-,文件总共才39050。服务器回了个416,回话里带Content-Range: bytes */39050——星号的意思是「你要的段不存在,但全文就这么长,自己看着办」。

这个416白眼还有个妙用。我对一个已经完整下载的文件再跑一次wget -c,它本地记录「已有39050字节」,于是开口要bytes=39050-——从文件末尾往后要,等于要了个不存在的段。服务器回416,带着bytes */39050。wget看到就明白了:我要的位置正好是文件总长,一个字节不缺,下完了,收工。续传逻辑里「确认完成」就是这么干的——不是数着字节数够了才停,而是多要一次,让服务器用416盖个章。206负责给段、416负责盖章,这对兄弟在404和502那篇状态码总账里提过名字,这里是它俩真正干活的地方。

顺带补一句,HTTP里有加密那一层我之前写过http和https的区别,Range这套要段的规矩在两种协议下是一样的,抓包看到的东西没差别。

续传前的对暗号:文件还是那个文件吗

知道要段了,断了的下载怎么接上?其实就三步:下载器在本地存着已下载的字节数,比如下到3.9G断了,续传时发Range: bytes=4187593088-,服务器从断点往后给,收到的字节直接追加到本地文件末尾。

但这里藏着一个坑:服务器上的文件还是原来那个文件吗?要是这中间站长更新过文件,你手里3.9G是旧版的头,接上新版的尾巴,拼出来一个四不像,装系统装出鬼来。

所以续传前要对暗号。第一次下载时,响应头里带着两个凭据:ETag和Last-Modified——我这组实验里是etag: "6ac4ef6d-988a"加一个修改时间。续传时下载器把这两个凭据原样带回去,服务器一对:对得上,206接着给;对不上,直接回200把整个新文件塞给你,等于强制从头。这套凭据跟浏览器缓存用的304是同一伙的,网页一直显示旧内容那篇里讲过它们怎么工作。

命令行下最直观的是wget -c,断在哪从哪续;curl对应的是curl -C -,横杠表示「断点位置你自己算」。浏览器直接下载用的也是这套,只是它不给你看过程。

多线程下载器在干嘛:切4段拼回去,我验了md5

弄懂Range,多线程下载器的底牌就掀开了。所谓8线程、16线程,就是把文件总长除以线程数,每条线程发一个不同区间的Range,并行拉,最后在本地拼回一个文件。

我把那张39050字节的图切成4段做了回实验:线程一要0-9762,线程二要9763-19525,线程三要19526-29287,线程四要29288-39049。四条请求同时发,各拉回9763、9763、9762、9762字节,按顺序拼接,得到39050字节。然后跟完整下载的原文件做md5比对——ce42d41f3e6ac0080839fa144a6702d2,两个一模一样。字节级还原,中间没有任何校验补丁,因为每一段就是从原文件上剁下来的。

那多线程为什么显得快?说实话它没有「提速」,你的宽带还是那条宽带,带宽、协商速率、实测速度本来就是三本账。它干的事是占满管道:单线程下载时,如果服务器单连接限速500KB/s,或者传输中间有空闲等待,管道就浪费了;8条连接各限500KB/s,加起来就是4MB/s。早年下载工具吹的「加速」,多半是这种绕单连接限速的玩法。现在BT下载器内置的也是分段思路,NAS下载机那篇里qBittorrent下载时你看到的那些连接数,就是对端分块并行拉的现场。

哪些东西天生续不了

也不是所有下载都能续。断点续传要三个条件凑齐:服务器认Range、文件是静止的、下载器会记进度。

我拿一个测试接口试过,请求头里明明白白发了个Range,人家理都不理,直接回200,把整个文件从头塞了一遍。这就是不支持Range的服务端——注意它不报错,静默降级成全量重传,你以为是续传,其实早重头来了。有些网盘免费用户限速,单线程几百KB,就是靠不认Range或者掐多线程来限的,会员「加速」说白了是放开这些口子。

还有一种续不了:动态生成的内容。有些页面是请求那一刻才拼出来的,两次请求拼出来的东西都不一样,字节位置对不上,Etag也对不上,只能整份拿。判断办法很简单,看第一次响应头里有没有Accept-Ranges: bytes这行,有就是明码标价支持分段;没有的话,多半只能怪服务器了。

一张表收尾

你遇到的情况背后是谁在干活你能不能插手
下载断了点「继续」,从断点接着来Range请求 + 206响应 + Etag对暗号换认Range的下载源,别用浏览器硬下
多线程下载比单线程快好几倍多条Range并行,绕单连接限速线程数8-16够用,再多服务器可能拒
续传后文件装不上、打不开文件中途变过,头尾两个版本删了重下,别信拼出来的文件
点继续发现进度归零重头下服务器回200全量,不认Range换下载工具或换源,会员加速也是这条路
视频拖进度条秒响应播放器发Range只拉那一段不用插手,天生的

顺序上给个收尾:大文件先确认响应头里有Accept-Ranges: bytes再下;下载中断了别删本地半截文件,点续传;续传完装系统前校验一下官方给的md5,花十秒钟,免得装到一半才发现拼坏了。表弟那个97%,后来wget -c三分钟接完了,前面的3.9G一个字节没白下。

展开全文


版权说明 手机扫码阅读
版权所有:《数巢笔记》 => 《断点续传是什么原理?下载断了接着下,我抓包看到Range和206这么配合》
本文地址:https://www.shunot.com/lybk/1156.html
除非注明,文章均为 《SHUNOT》 原创,欢迎转载!转载请注明本文地址,谢谢。

发表评论

联系我们

在线咨询:点击这里给我发消息

微信号:master_135

工作日:9:00-23:00,节假日休息

扫码关注