Android 文件断点上传器[多用户并发访问]

本文介绍了一种使用TCP/IP协议实现在Android上进行文件断点续传的方法,尤其适用于网络不稳定和上传大文件的场景。服务器端通过生成唯一sourceid关联文件,保存上传进度,客户端根据sourceid获取断点位置,实现续传。详细代码和项目Demo可供下载参考。
摘要由CSDN通过智能技术生成

通过TCP/IP(SOCKET)协议实现文件断点上传(实现多用户并发访问)。

HTTP不支持文件断点续传,所以无法使用HTTP协议。

场景:
1. 网络不稳定,导致上传失败,下次不是从头开始,而是从断点开始上传;
2. 上传大文件,无法http上传,因为web服务器考虑到安全因素,会限制文件大小,一般10+m。

此文件断点上传器使用自定义协议。

这里写图片描述

服务器为上传的文件在服务器端生成唯一的sourceid关联上传文件,当客户端上传文件时,首次的sourceid为空,服务端先判断sourceid是否为空,如果为空,生成sourceid和下载断点position=0返回给客户端,如果不为空,把之前记录的sourceid和上次记录的当前下载断点position返回给客户端,客户端指定从文件的position位置开始上传数据。当下一次传文件时,服务器由sourceid关联到文件,找到sourceid对应文件的当前下载断点position返回给客户端,客户端从指定位置position开始上传数据。

服务器端:
这里写图片描述
FileServer.java

package cn.itcast.net.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PushbackInputStream;
import java.io.RandomAccessFile;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import cn.itcast.utils.StreamTool;

public class FileServer {
   

     private ExecutorService executorService;//线程池
     private int port;//监听端口
     private boolean quit = false;//退出
     private ServerSocket server;
     private Map<Long, FileLog> datas = new HashMap<Long, FileLog>();//存放断点数据

     public FileServer(int port){
         this.port = port;
         //创建线程池,池中具有(cpu个数*50)条线程
         executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 50);
     }
     /**
      * 退出
      */
     public void quit(){
        this.quit = true;
        try {
            server.close();
        } catch (IOException e) {
        }
     }
     /**
      * 启动服务
      * @throws Exception
      */
     public void start() throws Exception{
         server = new ServerSocket(port);
         while(!quit){
             try {
               Socket socket = server.accept();
               //为支持多用户并发访问,采用线程池管理每一个用户的连接请求
               executorService.execute(new SocketTask(socket));
             } catch (Exception e) {
               //  e.printStackTrace();
             }
         }
     }

     private final class SocketTask implements Runnable{
   
        private Socket socket = null;
        public SocketTask(Socket socket) {
            this.socket = socket;
        }

        public void run() {
            try {
                System.out.println("accepted connection "+ socket.getInetAddress()+ ":"+ socket.getPort());

                //创建回退流对象,将拆解的字节数组流传入
                //PushbackInputStream类继承了FilterInputStream类是iputStream类的修饰者。
                //提供可以将数据插入到输入流前端的能力。能够插入的最大字节数与推回缓冲区的大小相关。
                PushbackInputStream inStream = new PushbackInputStream(socket.getInputStream());

                //得到客户端发来的第一行协议数据:Content-Length=143253434;filename=xxx.3gp;sourceid=
                //如果用户初次上传文件,sourceid的值为空。
                String head = StreamTool.readLine(inStream);
                System.out.println(head);

                //黑客假如注入很长的第一行数据,那么服务器肯定会由于内存溢出而崩溃
                //实际项目中这里要判断第一行协议内容不能超过多长,设置一个长度上线,防止内存溢出异常。
                if(head!=null){
                    //下面从协议数据中提取各项参数值
                    String[] items = head.split(";");
                    String filelength = items[0].substring(items[0].indexOf("=")+1);
                    String filename = items[1].substring(items[1].indexOf("=")+1);
                    String sourceid = items[2].substring(items[2].indexOf("=")+1);      
                    long id = System.currentTimeMillis();//生产资源id,如果需要唯一性,可以采用UUID
               
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值