JAVA基础知识之网络编程——-网络基础(多线程下载,get,post)
Posted 云中之歌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA基础知识之网络编程——-网络基础(多线程下载,get,post)相关的知识,希望对你有一定的参考价值。
本文主要介绍java.net下为网络编程提供的一些基础包,InetAddress代表一个IP协议对象,可以用来获取IP地址,Host name之类的信息。URL和URLConnect可以用来访问web资源,URLDecode和URLEncode用来转换字符串。 本文会写两个例子来演示java网络编程的一些基本用法。
第一个例子,写一个程序用来模拟多线程下载。
本例中用到的技术有,
多线程——多个线程同时读文件写文件,可以加快下载速度,
线程池——在本例中线程池不是必须,甚至是多余,只不过是为了演示线程池的简单用法
断点下载/上传——用RandomAccessFile的seek方法可以直接从某个中间位置读取或者写入文件
URLConnection——建立网络连接,读取网络数据的基本方法
iostring——网络IO,建立在URLConnection上的网络IO stream
有几个关键点值得注意,
- 一是使用了URL的实例建立了一个httpURLConnection实例, 通过这个实例的getInputStream(继承自父类)可以返回一个instream对象进行读数据操作
- 二是由于是多线程从远程读文件,每个文件将读取一块文件,文件大小按线程数平分,单个线程文件块 = 文件总大小 / 线程总数,使用RandomAccessFile的方式可以按指定位置读写文件
- 使用RandomAccessFile的seek方法,计算每个线程下载的起始位置
- 使用inStream的skip方法计算每次从网络读取数据的位置
具体实现如下, 先写一个工具类DownUtil, 其中写了一个内部线程类download,还定义了一个线程池,将多个线程类的实例提交给线程池管理,
1 package network; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.RandomAccessFile; 6 import java.net.HttpURLConnection; 7 import java.net.MalformedURLException; 8 import java.net.URL; 9 import java.util.concurrent.ExecutorService; 10 import java.util.concurrent.Executors; 11 12 13 public class DownUtil { 14 //下载资源路径 15 private String path; 16 private String targetFile; 17 //线程数量 18 private int threadNum; 19 //下载线程对象 20 private DownThread[] threads; 21 //下载文件总大小 22 private int fileSize; 23 //定义一个线程池,在构造函数中初始化成具体类型的线程池 24 ExecutorService pool; 25 26 public DownUtil(String path, String targetFile, int threadNum) { 27 this.path = path; 28 this.targetFile = targetFile; 29 this.threadNum = threadNum; 30 this.threads = new DownThread[threadNum]; 31 this.pool = Executors.newFixedThreadPool(threadNum); 32 } 33 34 public void download() throws IOException { 35 URL url = new URL(path); 36 HttpURLConnection conn = (HttpURLConnection)url.openConnection(); 37 conn.setConnectTimeout(5*1000); 38 conn.setRequestMethod("GET"); 39 conn.setRequestProperty("accept", "*/*"); 40 /* 41 conn.setRequestProperty("Accept", "image/gif, image/jpg, image/png, " 42 + "application/x-shockwave-flash, application/xam+xml, " 43 + "application/vnd.ms-xpsdocument, application/x-ms-xbap, " 44 + "application/x-ms-application, application/vnd.ms-excel, " 45 + "application/vnd.ms-powerpoint, application/msword, **"); 46 */ 47 conn.setRequestProperty("Charset", "multipart/form-data"); 48 conn.setRequestProperty("Connection", "Keep-Alive"); 49 //得到文件大小 50 fileSize = conn.getContentLength(); 51 conn.disconnect(); 52 //每个线程要下载的文件部分的大小 53 int currentPartSize = fileSize / threadNum + 1; 54 RandomAccessFile file = new RandomAccessFile(targetFile , "rw"); 55 file.setLength(fileSize); 56 file.close(); 57 for ( int i = 0; i < threadNum; i++ ) { 58 // 计算每个线程下载的开始位置 59 int startPos = i * currentPartSize; 60 //每个线程使用一个RandomAccessFile进行下载 61 RandomAccessFile currentPart = new RandomAccessFile(targetFile, "rw"); 62 //定位该线程的下载位置 63 currentPart.seek(startPos); 64 //创建下载线程 65 threads[i] = new DownThread(startPos, currentPartSize, currentPart); 66 //将单个线程提交到线程池,线程会启动 67 pool.submit(threads[i]); 68 } 69 pool.shutdown(); 70 } 71 72 //获取下载的完成百分比 73 public double getCompleteRate() { 74 //统计多个线程已经下载的总大小 75 int sumSize = 0; 76 for (int i = 0; i< threadNum; i++) { 77 sumSize += threads[i].length; 78 } 79 return sumSize * 1.0 / fileSize ; 80 } 81 82 private class DownThread implements Runnable { 83 //当前线程的下载位置 84 private int startPos; 85 //当前线程负责下载的大小 86 private int currentParSize; 87 //当前线程需要下载的文件块 88 private RandomAccessFile currentPart; 89 //该线程一下载字节数 90 public int length; 91 92 public DownThread(int startPos, int currentPartSize, 93 RandomAccessFile currentPart) { 94 this.startPos = startPos; 95 this.currentParSize = currentPartSize; 96 this.currentPart = currentPart; 97 } 98 99 public void run() { 100 try { 101 URL url = new URL(path); 102 HttpURLConnection conn = (HttpURLConnection)url.openConnection(); 103 conn.setConnectTimeout(5*1000); 104 conn.setRequestMethod("GET"); 105 conn.setRequestProperty("accept", "*/*"); 106 /* 107 conn.setRequestProperty("Accept", "image/gif, image/jpg, image/png, " 108 + "application/x-shockwave-flash, application/xam+xml, " 109 + "application/vnd.ms-xpsdocument, application/x-ms-xbap, " 110 + "application/x-ms-application, application/vnd.ms-excel, " 111 + "application/vnd.ms-powerpoint, application/msword, **"); 112 */ 113 //conn.setContentType(conn.getContentType()); 114 conn.setRequestProperty("Charset", "UTF-8"); 115 conn.setRequestProperty("Connection", "Keep-Alive"); 116 InputStream inStream = conn.getInputStream(); 117 //跳过startPos之前的内容 118 inStream.skip(this.startPos); 119 byte[] buffer = new byte[1024]; 120 int hasRead = 0; 121 // 读取网络数据,写入本地文件 122 while (length < currentParSize && (hasRead = inStream.read(buffer)) != -1) { 123 currentPart.write(buffer, 0 ,hasRead); 124 length += hasRead; 125 } 126 currentPart.close(); 127 inStream.close(); 128 } catch (Exception e) { 129 e.printStackTrace(); 130 } 131 } 132 } 133 }
在主程序中初始化工具类DownUtil,然后每隔固定时间去检查一次下载进度,
1 package network; 2 3 import java.io.IOException; 4 5 public class MultiThreadDown { 6 public static void main(String[] args) throws IOException, InterruptedException { 7 // 初始化DownUtil 8 final DownUtil downUtil = new DownUtil( 9 "http://sw.bos.baidu.com/sw-search-sp/software/7d662d80a3d85/npp_7.2_Installer.exe", 10 "notepad.exe",4); 11 //开始下载 12 downUtil.download(); 13 Thread monitor = new Thread(new Runnable(){ 14 15 @Override 16 public void run() { 17 while(downUtil.getCompleteRate() <= 1) { 18 //每隔1秒查看一次完成进度 19 System.out.println("已完成:"+downUtil.getCompleteRate()); 20 try { 21 Thread.sleep(1000); 22 } catch (InterruptedException e) { 23 // TODO Auto-generated catch block 24 e.printStackTrace(); 25 } 26 } 27 } 28 29 }); 30 monitor.start(); 31 monitor.join(); 32 System.out.println("下载完成"); 33 } 34 }
程序是以下载一个QQ程序为例, 下面是执行结果,
1 已完成:0.0 2 已完成:0.11293072177355859 3 已完成:0.278329429397341 4 已完成:0.4422385019008841 5 已完成:0.5001718809754122 6 已完成:0.5001718809754122 7 已完成:0.6514949778417655 8 已完成:0.9376444643781072 9 下载完成
本例中,如果调整线程个数,经过测试,线程数越多,下载反而越慢,估计是因为创建IO时间占用太多,毕竟下载一个文件本来就不用多久。 看来对于小文件下载但是单线程快。
以上是关于JAVA基础知识之网络编程——-网络基础(多线程下载,get,post)的主要内容,如果未能解决你的问题,请参考以下文章