【第22期】观点:IT 行业加班,到底有没有价值?

网络编程--JAVA之多线程下载

原创 2016年06月01日 10:55:58

今天,我来针对java中的一些网络编程中的多线程下载来进行简单的解析。

首先理解一下多线程下载的原理
这里写图片描述
- 如上图所示,有三个人A、B、C去下载MP4,当假设服务器的带宽网速是12M/s,那么三个人每人一个线程就平均每条线程可以分到4M/s

  • 但是如果A将占据两条线程,那么现在总共就有4条线程了,
    如图:
    这里写图片描述
    也就是说12M/s的网速平均每个线程是可以分到3M/s,那么A就分到了6M/s,B分到了3M/s,C也是分到了3M/s,那明显A下载MP4的速度要加快许多,这就是表现出来的多线程的下载一个简单的原理优势。

接着,我们来梳理一下实现多线程下载的步骤:

  1. 多线程下载其实就是将资源按线程多少来分段的去下载,那么要分段,首先就得知道所需下载资源的大小,所以先拿到资源大小。

  2. 先在内存中创建一个与所下资源,在这里也就是MP4大小的文件,先占好一个足够容下MP4大小的容量。
    原因:是因为如果不先占好位置的话,那么假如MP4的大小是200M,那么假设现在内存是205M,按理来说是内存是够的,那当我们开始下载MP4的中途中,我又下了一个15M的音乐,那么接下来的内存就不够MP4了,这就是为什么刚开始就要占好位置。)

  3. 接下来就要确定每条线程的开始位置和结束位置了。
    先来看个图:(ps:图画的丑,画板不是很会用,莫怪~~~)
    这里写图片描述
    在这里我们先假设MP4的大小为10M,现在我开三个线程去分段的下载这个资源,本来应该均分的,但是这里10除以3是除不尽的,那么也如图这样分配,最后一个分配四个。所以在这我们要确定每个线程在文件中开始位置和结束的位置。

  4. 接下来就真的是用HttpURLconnection以及IO流的知识来进行文件的下载,在这也就是文件的写入。(如不懂IO流,可以参照我转载的上篇博客,IO流详解)


Main代码中:

package com.ecjtu.mutilThread;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class Main {


    /*
     * 先拿到需要下载文件的大小,先不用拿到流
     */
    public static final String PATH = "http://192.168.150.1:8088/txvpn_1.08.apk";

    public static int threadCount=3;///进行下载的数量

    public static void main(String[] args) {
        try {
            URL url = new URL(PATH);

            ///在这里用HttpURLConnection只是用来获取文件的大小
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(8000);
            connection.setReadTimeout(8000);

            if(connection.getResponseCode()==200){
                ///在这里就可以拿到文件的大小
                int length=connection.getContentLength();

                ///在这里先占个位置,也就是创建一个文件的大小的区间
                File file=new File("nihao.apk");
                ///随机文件,让该文件拥有需下载的文件的大小,从而达到占位置的作用
                ///在这里的第二个参数一班为rwd,不仅让他可读可写,并且会将数据刻在硬件上
                //RandomAccessFile的唯一父类是Object,与其他流父类不同。是用来访问那些保存数据记录的文件的,这样你就可以用seek( )方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和位置必须是可知的。
                RandomAccessFile ref=new RandomAccessFile(file,"rwd"); 
                ref.setLength(length);

                ref.close();

                int size=length/threadCount;


                for(int id=0;id<threadCount;id++){
                    //1.确定每个线程的下载区间
                    //2.确定完后,开始对应的子线程


                    ///在这里确定开始位置和结束位置
                    int startIndex=id*size;
                    int endIndex=(id+1)*size-1;

                    ///将最后一个线程的结束为止拿出单独,将剩余的长度全给最后一个
                    if(id==threadCount-1){
                        endIndex=length-1;
                    }

                    System.out.println("第"+id+"个线程的下载区间为"+startIndex+"-"+endIndex);

                    new DownLoadThread(startIndex, endIndex, PATH, id).start();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这个代码中主要就是实现上述步骤中的1、2、3的步骤,接下来的就是是实现一下IO流的操作即可。

DownLoadThread代码中:

package com.ecjtu.mutilThread;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;

public class DownLoadThread extends Thread {

    private int startIndex,endIndex,threadId;
    private String path;

    public DownLoadThread(int startIndex,int endIndex,String path,int threadId) {
        this.startIndex=startIndex;
        this.endIndex=endIndex;
        this.path=path;
        this.threadId=threadId;
    }

    @Override
    public void run() {

        URL url;

        try {               
       ///这里才是利用HttpURLConnection拿到需要下载的真正的输入流
            url=new URL(path);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(8000);
            connection.setReadTimeout(8000);

            ///在这里用HttpURLConnection的设置请求属性的方法,来请求获取每一段的信息(在这里的格式书写是一样的,固定的)。
            connection.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);

            ///这里的206是代表上面的区段请求的响应的返回码
            if(connection.getResponseCode()==206){

                ///接下就是输入流的一些操作
                InputStream is=connection.getInputStream();

                File file=new File("nihao.zip");
                RandomAccessFile ref=new RandomAccessFile(file,"rwd"); 
                ref.seek(startIndex);///标志开始位置,可以让线程在文件中从不同位置开始存储

                byte[] b=new byte[1024];
                int len=0;
                int total = 0;

                while((len=is.read(b))!=-1){

                    ref.write(b, 0, len);

                    total+=len;
                    System.out.println("第"+threadId+"条线程的下载"+total);

                }
                ref.close();
                System.out.println("第"+threadId+"条线程的下载结束");
            }

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        super.run();
    }
}

运行的结果:

这里写图片描述


注意,在Main方法中,因为我这里是用到了Tomacat,将我这里的txvpn_1.08.apk这个文件放在了本地的Tomacat文件夹中的/webapps/root下的,所以在这我可以直接用自己的IP地址加Tomacat上设置的端口号开实现下载,如果不用Tomacat,去网上找个资源链接下载也是可以的。

接下来一篇,我将在这篇博客的基础上,加上现在普遍的断点续存,实现完整的多线程下载+断点续存。

版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

【Java】网络编程的简单应用,多线程下载最佳实践

【Java】网络编程笔记 package com.demo.networkprogram; import java.io.InputStream; import java.io.R...

Java中用多线程实现网络编程

要學會Java網絡編程,首先要对網絡通讯知识有一定的初步的了解,如网络OSI七层模型,常用的網絡協議,如tcp/ip,Http,FTP等協議,讀者可以從網上獲取這些知識,來進一步的了解,有助于Java的網絡編程,在此就不講這些內容了.下我們主要看一下如何在Java中進行網絡編程.   我們現在來實現一個服務器和多個客戶端時行網絡通訊的功能. 1. 使用Eclipse IDE,首先創建一個java項目:MultiThreadSocket 并讓它繼承Thread類 packa

网络编程--JAVA之多线程下载后续:断点续存

这篇博客就是接在我上篇博客网络编程–JAVA之多线程下载的基础上来实现的。首先,我来说一下断点续存能解决啥问题: 假如当我们在进行MP4下载时,如果突然出现人为的中断或者意外的中断,那么当我们再次...

介绍一本JAVA多线程的和网络编程的书

多线程:Java Concurrency in Practice     多线程的书:《Java Concurrency in Practice》 此书的下载  http://www.blogjava.net/chenpengyi/archive/2007/10/18/153977.html 网络:《Java网络编程(第三版)》 作者: Elliotte Rusty Harold     多线程 Java Concurrency in Pract
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)