您的位置:首页 > 理论基础 > 计算机网络

Android:网络:多线程下载(原理)

2016-01-04 10:08 513 查看
使用多线程下载文件可以更快完成文件的下载,多线程下载文件之所以快,是因为其抢占的服务器资源多。如:假设服务器同时最多服务100个用户,在服务器中一条线程对应一个用户,100条线程在计算机中并非并发执行,而是由CPU划分时间片轮流执行,如果A应用使用了99条线程下载文件,那么相当于占用了99个用户的资源,假设一秒内CPU分配给每条线程的平均执行时间是10ms,A应用在服务器中一秒内就得到了990ms的执行时间,而其他应用在一秒内只有10ms的执行时间。就如同一个水龙头,每秒出水量相等的情况下,放990毫秒的水

肯定比放10毫秒的水要多。

多线程下载的实现过程:

1>首先得到下载文件的长度,然后设置本地文件

的长度。

HttpURLConnection.getContentLength();

RandomAccessFile file = new
RandomAccessFile("QQWubiSetup.exe","rwd");

file.setLength(filesize);//设置本地文件的长度

2>根据文件长度和线程数计算每条线程下载的数据长度和下载位置。如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如上图所示。

3>使用Http的Range头字段指定每条线程从文件的什么位置开始下载,下载到什么位置为止,如:指定从文件的2M位置开始下载,下载到位置(4M-1byte)为止,代码如下:

HttpURLConnection.setRequestProperty("Range","bytes=2097152-4194303");

4>保存文件,使用RandomAccessFile类指定每条线程从本地文件的什么位置开始写入数据。

RandomAccessFilethreadfile = new
RandomAccessFile("QQWubiSetup.exe ","rwd");

threadfile.seek(2097152);//从文件的什么位置开始写入数据

上面是使用RandomAccessFile的方式,其实也可以使用多个文件保存相关联的线程的数据,待所有线程完成之后合并文件并删除原来的文件即可。



public class MulThreadDownloader {

    public static void main(String[] args) throws Exception {
        String path = "http://192.168.1.100:8080/web/QQWubiSetup.exe";

        int threadsize = 3;//3个线程下载

        new MulThreadDownloader().download(path, threadsize);

    }

    private void download(String path, int threadsize) throws Exception {

        URL downpath = new URL(path);

        HttpURLConnection conn = (HttpURLConnection) downpath.openConnection();

        conn.setConnectTimeout(5000);
        conn.setRequestMethod("HEADER");

        if(conn.getResponseCode() == 200){

            int length = conn.getContentLength();//获取网络文件的长度

            File file = new File(getFileName(path));

            RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");//生成本地文件,立即写入模式

            accessFile.setLength(length);

            accessFile.close();


            //计算每条线程负责下载的数据量

            int block = length % threadsize == 0 ? length / threadsize : length / threadsize +1;

            for(int threadid = 0 ; threadid < threadsize ; threadid++){

                new DownloadThread(threadid, downpath, block, file).start();

            }

        }

    }

    //负责下载操作

    private final class DownloadThread extends Thread{

        private int threadid;//线程id

        private URL downpath;//下载路径

        private int block;//本条线程下载量

        private File file;//访问的文件

        

        public DownloadThread(int threadid, URL downpath, int block, File file) {

            this.threadid = threadid;

            this.downpath = downpath;

            this.block = block;

            this.file = file;

        }

        public void run() {

            int startposition = threadid * block;//从网络文件的什么位置开始下载数据

            int endposition = (threadid+1) * block - 1;//下载到网络文件的什么位置结束


            //指示该线程要从网络文件的startposition位置开始下载,下载到endposition位置结束

            //Range:bytes=startposition-endposition

            try{

                RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");

                accessFile.seek(startposition);//移动指针到文件的某个位置

                HttpURLConnection conn = (HttpURLConnection) downpath.openConnection();

                conn.setConnectTimeout(5000);

                conn.setRequestMethod("GET");

                conn.setRequestProperty("Range", "bytes="+ startposition+ "-"+ endposition);

                InputStream inStream = conn.getInputStream();

                byte[] buffer = new byte[1024];

                int len = 0;

                while( (len = inStream.read(buffer)) != -1 ){

                    accessFile.write(buffer, 0, len);

                }


                accessFile.close();

                inStream.close();

                System.out.println("第"+ (threadid+1)+ "线程下载完成");

            }catch (Exception e) {

                e.printStackTrace();

            }

        }

    }

    /**

     * 获取文件名称

     * @param path 下载路径

     * @return

     */
    private static String getFileName(String path) {

        return path.substring(path.lastIndexOf("/")+ 1);

    }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: