断点续传的核心原理
你有没有遇到过下载大文件时网络突然断了,重新开始就得从头再来?这时候“断点续传”就派上用场了。它的本质其实不复杂:记录已经下载的部分,在中断后从断掉的地方继续,而不是重来。
实现的关键在于“记住位置”。就像你看小说看到第50页,合上书明天接着从51页看一样,断点续传就是让程序知道上次下载进行到了哪个字节。
客户端与服务器的配合
光客户端记住了位置还不行,还得服务器支持才行。HTTP 协议里有个叫 Range 的请求头,专门干这事。当你想从第1024字节继续下载,客户端就发一个请求:
GET /file.zip HTTP/1.1\nHost: example.com\nRange: bytes=1024-如果服务器支持断点续传,它会返回状态码 206 Partial Content,并附上从1024字节开始的数据。如果不支持,就会返回 200,并发整个文件。
本地如何保存断点信息
下载工具一般会在本地存一个临时文件或数据库记录,比如 file.zip.download,里面记着当前已下载的字节数、文件总大小、下载源地址等。万一中途崩溃,重启后先读这个文件,再向服务器请求对应区间的片段。
举个例子,你下一部电影,2GB 大小,下到1.5GB时断网了。恢复后,程序查记录发现已下1.5GB,就直接请求从第1,610,612,736字节开始的数据,跳过前面的部分。
多线程下载中的断点管理
现在很多下载器都用多线程,把文件切成几段同时下。比如分成4段,每段单独请求一个字节区间。这种情况下,每一段都要独立记录进度。哪怕某一段失败了,也只需要重试那一段,不影响其他部分。
代码逻辑大致如下:
start = segment_start_byte\nend = segment_end_byte\nrequest_headers = {\n "Range": `bytes=${start}-${end}`\n}\nsend_request(url, headers=request_headers)每段下载完成后,标记该段已完成。所有段都下完,再合并成完整文件,最后删掉临时记录。
实际应用中的细节处理
不是所有服务器都默认支持 Range 请求。有些Nginx配置没开,或者动态生成的文件(如PHP输出)没设置好响应头,就会导致断点续传失效。这时候即使客户端发了 Range,服务器还是返回整个文件或者400错误。
另外,文件在服务端被更新了也不行。比如你下了一半,服务器上的文件变了,再续传可能数据错乱。所以一些下载器会校验ETag或Last-Modified,发现文件变动就自动清记录重下。
日常用的迅雷、IDM、wget 都实现了这套机制。比如 wget 加 -c 参数就是启用断点续传:
wget -c https://example.com/large-file.iso只要服务器点头,它就能接着下;不行就乖乖从头开始。”}