弱网下视频分片上传:断点续传、排队上传、失败重试、云端溯源绑定

发布时间:2026/10/25 14:47:31

弱网下视频分片上传:断点续传、排队上传、失败重试、云端溯源绑定 弱网下视频分片上传断点续传、排队上传、失败重试、云端溯源绑定大家好我是黒漂技术佬。视频专题第二篇也是系列的倒数第二篇咱们聊视频上传。录好的视频存在本地没用出问题的时候得能调出来看。但4G弱网环境下传一个几MB的视频都可能断好几次传一半断了重传又浪费流量。今天给大家一套工业级的视频上传方案断点续传、排队调度、优先级管理、云端绑定全套都有。一、为什么视频上传是个难题先说说4G环境下传视频的痛点上传的几大难题网络不稳定传一半断了重传又得从头来浪费流量带宽有限4G上传带宽本来就小视频传起来慢不能影响业务上传占满带宽开门指令延迟了就麻烦了流量成本视频文件不小传多了流量费扛不住要能溯源传上去的视频得能跟订单、事件对应上核心目标稳定传上去不影响业务尽量省流量传完能对应上。二、分片上传与断点续传这是大文件上传的标准方案视频上传必须上。什么是分片上传把一个大视频文件切成一小块一小块的一块一块传原始视频video.mp4 (8MB) ↓ 切片 分片10 ~ 1MB 分片21MB ~ 2MB 分片32MB ~ 3MB ... 分片87MB ~ 8MB ↓ 逐个上传 全部传完后服务端合并成完整文件分片大小怎么选分片大小优点缺点适用场景256KB失败重传损失小请求次数多开销大网络很差的场景512KB均衡-推荐大部分场景1MB请求少效率高失败损失大网络较好的场景售货柜推荐512KB一片兼顾效率和容错。断点续传原理传了一半断了下次接着传不从头来上传前先问服务端这个文件传了多少了服务端返回已上传的分片列表客户端跳过已经传完的从下一片开始传全部传完通知服务端合并客户端实现publicclassChunkUploader{privatestaticfinalintCHUNK_SIZE512*1024;// 512KB一片/** * 上传视频文件 */publicbooleanuploadVideo(StringfilePath,StringfileId){FilefilenewFile(filePath);longfileSizefile.length();Stringmd5FileUtils.getFileMD5(file);// 1. 先查询已上传的分片ListIntegeruploadedChunksqueryUploadedChunks(fileId,md5);// 2. 计算总分片数inttotalChunks(int)Math.ceil((double)fileSize/CHUNK_SIZE);// 3. 逐个上传未完成的分片for(inti0;itotalChunks;i){if(uploadedChunks.contains(i)){continue;// 已经传过了跳过}booleansuccessuploadChunk(file,i,fileId,md5,totalChunks);if(!success){// 这一片传失败了下次重试Log.w(Upload,分片 i 上传失败);returnfalse;}// 每传完一片更新进度updateUploadProgress(fileId,i1,totalChunks);}// 4. 全部传完通知服务端合并returncompleteUpload(fileId,md5,fileSize);}/** * 上传单个分片 */privatebooleanuploadChunk(Filefile,intchunkIndex,StringfileId,Stringmd5,inttotalChunks){// 读取分片数据byte[]chunkDatareadChunk(file,chunkIndex,CHUNK_SIZE);// 构造请求MultipartBody.BuilderbuildernewMultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart(file_id,fileId).addFormDataPart(chunk_index,String.valueOf(chunkIndex)).addFormDataPart(total_chunks,String.valueOf(totalChunks)).addFormDataPart(file_md5,md5).addFormDataPart(file,chunk_chunkIndex,RequestBody.create(MediaType.parse(video/mp4),chunkData));// 发送请求带超时RequestrequestnewRequest.Builder().url(UPLOAD_URL).post(builder.build()).build();try{Responseresponseclient.newCall(request).execute();returnresponse.isSuccessful();}catch(IOExceptione){returnfalse;}}}MD5校验每个分片和整个文件都要校验防止传错了分片级每片传完校验MD5不对就重传这一片文件级全部传完校验整个文件的MD5确保完整三、上传队列与优先级调度不是所有视频都一样急分优先级排队传。优先级划分优先级视频类型上传时机说明最高异常事件视频立即上传异常开门、告警、人工调取高投诉/纠纷订单视频优先上传用户投诉了后台申请调取中正常开门视频闲时上传普通交易不急低巡检/测试视频有剩余流量再传可有可无的上传队列实现publicclassUploadQueueManager{privatePriorityQueueUploadTaskqueuenewPriorityQueue((a,b)-Integer.compare(b.getPriority(),a.getPriority()));privateUploadTaskcurrentTask;privatebooleanisRunningfalse;/** * 添加上传任务 */publicvoidaddTask(UploadTasktask){// 去重同一个文件不要重复加if(isInQueue(task.getFileId())){return;}queue.offer(task);if(!isRunning){startNextTask();}}/** * 开始下一个任务 */privatesynchronizedvoidstartNextTask(){if(queue.isEmpty()){isRunningfalse;return;}// 先检查网络弱网下不传低优先级的if(!canUploadNow()){isRunningfalse;return;}currentTaskqueue.poll();isRunningtrue;// 异步上传newThread(()-{booleansuccesschunkUploader.uploadVideo(currentTask.getFilePath(),currentTask.getFileId());onTaskFinished(currentTask,success);currentTasknull;startNextTask();}).start();}}网络条件判断弱网的时候不传或者只传高优先级的privatebooleancanUploadNow(){intnetworkLevelNetworkManager.getNetworkLevel();switch(networkLevel){caseNET_LEVEL_GOOD:// 网络好都可以传returntrue;caseNET_LEVEL_NORMAL:// 一般只传中优先级及以上returncurrentTask.getPriority()PRIORITY_MEDIUM;caseNET_LEVEL_WEAK:// 弱网只传高优先级returncurrentTask.getPriority()PRIORITY_HIGH;caseNET_LEVEL_BAD:caseNET_LEVEL_DISCONNECTED:// 很差不传returnfalse;default:returnfalse;}}四、失败重试与流量控制失败重试策略上传失败了怎么办跟之前的重连一样指数退避publicclassUploadRetryPolicy{privatestaticfinallongBASE_DELAY10*1000;// 10秒起步privatestaticfinallongMAX_DELAY10*60*1000;// 最多10分钟privatestaticfinalintMAX_RETRY10;// 最多重试10次privateintretryCount0;publiclonggetNextDelay(){if(retryCountMAX_RETRY){return-1;// 超过最大次数放弃}longdelay(long)(BASE_DELAY*Math.pow(2,retryCount));delayMath.min(delay,MAX_DELAY);retryCount;// 加随机抖动return(long)(delay*(0.8Math.random()*0.4));}publicvoidreset(){retryCount0;}}上传限速上传不能占满带宽不然影响MQTT等核心业务/** * 限速输出流控制上传速度 */publicclassRateLimitOutputStreamextendsOutputStream{privatelongbytesPerSecond;// 每秒最多传多少字节privatelongstartTime;privatelongbytesWritten;Overridepublicvoidwrite(byte[]b,intoff,intlen)throwsIOException{// 计算当前速度超了就sleep一下longelapsedSystem.currentTimeMillis()-startTime;if(elapsed0){longcurrentSpeedbytesWritten*1000/elapsed;if(currentSpeedbytesPerSecond){longsleepTime(bytesWritten*1000/bytesPerSecond)-elapsed;if(sleepTime0){try{Thread.sleep(sleepTime);}catch(InterruptedExceptione){}}}}out.write(b,off,len);bytesWrittenlen;}}限速策略正常业务期间限制在 200KB/s 以内不抢业务带宽闲时凌晨可以放开到 512KB/s 甚至更高弱网下进一步降低或者暂停上传五、闲时上传与流量管控闲时上传策略普通视频不着急留到流量便宜的时候传publicclassIdleTimeUploadScheduler{// 闲时段凌晨2点到6点privatestaticfinalintIDLE_START_HOUR2;privatestaticfinalintIDLE_END_HOUR6;/** * 判断当前是不是闲时 */publicbooleanisIdleTime(){inthourCalendar.getInstance().get(Calendar.HOUR_OF_DAY);returnhourIDLE_START_HOURhourIDLE_END_HOUR;}/** * 调度上传任务 */publicvoidscheduleUpload(UploadTasktask){if(task.getPriority()PRIORITY_HIGH){// 高优先级立刻传uploadQueue.addTask(task);}else{// 低优先级等闲时再传pendingIdleTasks.add(task);}}}月流量配额控制每个月流量有限超了就不传非必要的publicbooleanhasEnoughTrafficForUpload(longfileSize){longmonthUsedTrafficMonitor.getMonthTraffic();longmonthLimitConfigManager.getMonthTrafficLimit();longremainingmonthLimit-monthUsed;// 剩余流量超过文件大小的2倍才传留余量returnremainingfileSize*2;}六、云端溯源绑定视频传上去了得能跟订单、事件对应起来。上传时带上业务信息publicclassVideoUploadInfo{privateStringfileId;// 文件唯一IDprivateStringdeviceNo;// 设备编号privateStringeventType;// 事件类型open/abnormal/shakeprivateStringrelatedOrderId;// 关联订单号privatelongstartTime;// 录像开始时间privateintduration;// 时长privateStringfileMd5;// 文件MD5privatelongfileSize;// 文件大小}云端存储结构视频存储/ ├── 设备编号/ │ ├── 20260708/ │ │ ├── 订单号1.mp4 │ │ ├── 异常事件_时间戳.mp4 │ │ └── ... │ └── 20260709/ │ └── ...按设备日期分目录文件名带订单号或事件信息后台管理系统可以直接按订单号查视频。回调通知传完了通知后台后台把视频和订单绑定privatevoidonUploadSuccess(UploadTasktask){// 更新数据库状态VideoRecordDb.getInstance().updateUploadStatus(task.getFileId(),UPLOAD_STATUS_SUCCESS,System.currentTimeMillis());// 通知后台JSONObjectpayloadnewJSONObject();payload.put(file_id,task.getFileId());payload.put(video_url,task.getRemoteUrl());payload.put(related_order_id,task.getRelatedOrderId());payload.put(event_type,task.getEventType());MqttManager.publish(device/DeviceInfo.getDeviceNo()/video/uploaded,payload.toString(),1);}七、上传状态持久化APP重启了上传进度不能丢。上传任务持久化把待上传的任务存数据库CREATETABLEupload_task(idINTEGERPRIMARYKEYAUTOINCREMENT,file_idVARCHAR(64)UNIQUE,-- 文件IDfile_pathVARCHAR(256),-- 本地路径priorityINTEGER,-- 优先级event_typeVARCHAR(32),-- 事件类型related_idVARCHAR(64),-- 关联IDstatusINTEGERDEFAULT0,-- 0待上传 1上传中 2成功 3失败uploaded_chunksTEXT,-- 已上传分片列表JSONretry_countINTEGERDEFAULT0,-- 重试次数create_timeBIGINT,update_timeBIGINT);启动恢复APP启动时从数据库恢复未完成的任务publicvoidrestorePendingTasks(){ListUploadTaskpendingUploadTaskDb.getInstance().queryPendingTasks();for(UploadTasktask:pending){if(task.getStatus()UPLOAD_STATUS_UPLOADING){// 上次传了一半重置为待上传从断点继续task.setStatus(UPLOAD_STATUS_PENDING);}uploadQueue.addTask(task);}}八、踩坑经验坑1分片传完了但合并失败现象所有分片都显示传成功了但合并后的文件损坏原因某一片传的时候数据错了MD5没校验好解决每片传完服务端都校验MD5不对就让重传合并后再校验整个文件的MD5坑2上传过程中网络切换现象传一半WiFi切4GIP变了连接断了解决分片上传天然支持断点续传断了重新查进度接着传就行坑3视频还在录制就开始传现象文件还在写读出来的数据不完整解决录制完成、文件关闭后再加入上传队列上传前检查文件是否完整坑4大量视频同时上传把带宽占满现象批量恢复上传的时候几十个视频一起传MQTT都连不上了解决单队列串行上传同时只传一个加上传限速弱网下只传高优先级九、总结弱网视频上传的核心分片断点排队限速。分片上传512KB一片失败只重传一片省流量断点续传传了多少都记录重启断网都不怕优先级队列异常、投诉优先普通视频闲时再传上传限速不能抢业务带宽保证开门等核心功能优先流量控制月配额、闲时策略控制成本溯源绑定视频和订单、事件关联方便后台查询这套方案下来4G弱网环境下视频上传也能稳稳的不用再担心传一半断了白忙活。我是黒漂技术佬专注无人零售物联网实战。五大模块的12篇细分文章到这里就全部结束了下一篇是整个系列的收官总结把全链路的核心要点和踩坑经验串起来。有视频上传的坑欢迎私信交流大家一起避坑~
延伸阅读

更多相关文章

2026/10/24 3:07:08

BUUCTFYoungter-drive

考点:多线程 查壳脱壳 进入ida,直接进入main函数 sub_4110FF是输入flag的部分,flag有36个字符 main函数8-13行:有两个线程hObject、Thread 这段代码是使用C语言风格的Windows API函数来创建互斥体(Mutex)、…

2026/10/23 13:19:28

BUUCTF [UTCTF2020]basic-re

查壳 没有 进入ida看了之后发现与flag好像没关系,shiftF12发现可疑字符串,提交试一下成功了,flag{str1ngs_1s_y0ur_fr13nd}

2026/10/26 6:56:17

SAP SD返利结算全流程配置与避坑指南

简介:这份文档面向SAP SD模块顾问、财务结算人员及ERP实施学习者,系统讲解返利(Rebate)功能的完整使用方案,帮助解决返利协议配置、获利过账与结算冲销等实际业务难题。资源为1个docx文档,压缩包约481KB&am…

2026/10/26 6:56:17

AI驱动的安卓逆向工程工具链TRAE+JADX-AI-MCP实战指南

1. 项目背景与核心价值在移动安全研究领域,安卓逆向工程一直是技术门槛较高的专业方向。传统逆向分析需要工程师具备汇编语言、Java/Smali语法、APK文件结构等复合知识,一个简单的功能分析往往需要数小时甚至数天的静态分析与动态调试。TRAEJADX-AI-MCP这…

2026/10/26 6:56:17

Claude记忆机制原理与MEM-3P增强型Prompt实战框架

1. “claude-mem”不是官方功能,而是社区对Claude记忆机制的具象化命名最近在多个技术社区、AI工具讨论组和开发者私聊中,“claude-mem”这个词高频出现——它既不是Anthropic官网文档里的术语,也不在任何API Reference中被正式定义&#xff…

2026/10/26 6:56:17

text-to-cad落地指南:文字描述一键生成可编辑CAD图纸

从一条文字描述直接拿到一份可编辑的CAD图纸,这件事放在三年前还像是科幻片。但现在“text-to-cad”确实从论文和Demo走向了工程实践,我把它接到自己的日常工作流里已经跑了小半年。这篇就聊聊我实际用下来的思路、踩过的坑,以及怎么把它和传…

2026/10/26 6:56:17

利用过拟合实现大模型越狱攻击的技术解析

1. 项目概述:通过过拟合实现大模型越狱攻击这个研究项目提出了一种新颖的大语言模型(LLM)越狱攻击方法,仅需10个良性样本进行微调就能实现模型越狱。不同于传统需要大量恶意样本的攻击方式,该方法巧妙地利用过拟合现象…

2026/10/26 6:51:16

SIwave中文培训手册实战指南:从PCB导入到PI/SI仿真全流程

简介:SIwave中文培训手册面向从事高速PCB设计的工程师与电子相关专业学习者,聚焦信号完整性与电源完整性仿真这一核心技能,帮助读者从理论概念过渡到软件实操。手册从现代PCB设计挑战切入,系统讲解传输线、特性阻抗、反射系数、截…

2026/10/26 0:20:20

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/26 1:53:47

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/26 0:20:17

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/26 0:00:48

Nested Learning:解决AI灾难性遗忘的分层记忆架构

1. 为什么AI需要"记忆"能力?在传统深度学习模型中,我们常遇到一个根本性问题:模型在处理新任务时,往往会完全遗忘之前学到的知识。这种现象被业界称为"灾难性遗忘"(Catastrophic Forgetting)。想象一下&#…

2026/10/26 0:00:48

企业级大模型应用:OCR预处理、Dify编排与DeepSeek落地实战

1. 这不是“用大模型”,而是重构工作流的起点“大模型的应用和工具”——这八个字现在被贴在无数技术分享、招聘JD、内部立项书的标题栏里,但绝大多数人点进去后看到的,是零散的API调用示例、几个开源UI截图、或者一句“接入LLM就能降本增效”…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑