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时间占用太多,毕竟下载一个文件本来就不用多久。 看来对于小文件下载但是单线程快。

时间: 2025-01-02 09:16:59

JAVA基础知识之网络编程——-网络基础(多线程下载,get,post)的相关文章

Linux网络编程------网络编程基础

Socket(套接字),类似文件描述符,三种 1.流式套接字(SOCK_STREAM):可以提供可靠的.面向连接的通讯流,它使用TCP协议.TCP保证了数据传输的正确性和顺序性. 2.数据报套接字(SOCK_DGRAM):定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错,它使用数据报协议(UDP). 3.原始套接字(SOCK_RAW):直接基于IP协议. 网络地址 struct sockaddr用于记录网络地址: struct sockaddr { u_s

[转] - Linux网络编程 -- 网络知识介绍

(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户端        在网络程序中,如果一个程序主动和外面的程序通信,那么我们把这个程序称为客户端程序. 比如我们使用ftp程序从另外一        个地方获取文件的时候,是我们的ftp程序主动同外面进行通信(获取文件), 所以这个地方我们的ftp程序就是客户端程序. 服务端        和客户端相

Socket网络编程--网络爬虫(1)

我们这个系列准备讲一下--网络爬虫.网络爬虫是搜索引擎系统中十分重要的组成部分,它负责从互联网中搜集网页,采集信息,这些网页信息用于建立索引从而为搜索引擎提供支持,它决定着整个引擎系统的内容是否丰富,信息是否即时,因此其性能的优劣直接影响着搜索引擎的效果.网络爬虫的基本工作原理: (1)从一个初始URL集合中挑选一个URL,下载该URL对应的页面: (2)解析该页面,从该页面中抽取出其包含的URL集合,接下来将抽取的URL集合再添加到初始URL集合中: (3)重复前两个过程,直到爬虫达到某种停止

java学习--基础知识进阶第十二天--网络编程概述、UDP协议、TCP协议

今日内容介绍 u  网络编程概述 u  UDP u  TCP 第1章 网络编程概述 1.1 网络协议 通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样.在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式.传输速率.传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换. 网络通信协议有很多种,目前应用最广泛的是TCP/IP协议(Transmission Contro

Java中基于UDP协议的的网络编程(基础篇)

---恢复内容开始--- 一:什么是网络编程? 通俗的来说, 网络编程就是编写程序,让联网的两个或多个设备(例如计算机)之间进行数据传输.Java语言也支持网络编程,JDK提供的 java.net包提供了很多于网络编程相关的类,来支持网络编程方面的学习. 二:java网络编程所使用的协议? 有了计算机网络的基础,我们不难理解,在java中,网络编程是基于网络传输协议的. java网络编程,可以是基于TCP协议的,也可以基于UDP协议的.那么首先我们得知道tcp协议和udp两种协议的区别. 区别:

TCP/UDP网络编程的基础知识与基本示例(windows和Linux)

一.TCP编程的一般步骤 服务器端: 1.创建一个socket,用函数socket() 2.绑定IP地址.端口等信息到socket上,用函数bind() 3.开启监听,用函数listen() 4.接收客户端上来的连接,用函数accept() 5.收发数据,用函数send()和recv(),或者read()和write() 6.关闭网络连接 7.关闭监听 客户端: 1.创建一个socket,用函数socket() 2.设置要连接的对方IP地址和端口等属性 3.连接服务器,用函数connect()

linux云自动化运维基础知识11(ip网络 )

####1.ip基础知识####1.ipv42进制32位-----10进制 172.25.0.10/255.255.255.0172.25.0.10:ip地址255.255.255.0:子网掩码子网掩码255位对应的ip位为网络位子网掩码0对应的ip位为主机位 ####2.配置ip####<<图形化>>1.图形界面nm-connection-editor 2.文本化图形nmtui <<命令>>ifconfig 网卡 ip netmask    ##临时设定

网络编程—网络基础概览、socket,TCP/UDP协议

网络基础概览 socket概览 socket模块-TCP/UDP的实现 TCP/UDP总结 网络基础概览 osi七层协议各层主要的协议 # 物理层传输电信号1010101010 # 数据链路层,以太网协议,arp协议.对这些信号进行分组,同时规范了分组形式--以太网协议,头部是mac地址中间是信息, # 网络层:ip协议,arp协议帮忙找到mac地址,ip,子网掩码,网关(下面有一些简单概括) # 传输层:tcp协议,udp协议 # (socket)就是一组接口,将复杂的tcp协议和udp协议隐

网络编程之基础篇一

1.软件开发的架构: 1) C/S 架构:即client 和 server, 客服端与服务器端架构,这种架构是从用户层面来划分的,这里的客户端泛指客户端应用程序exe,程序要先安装,对用户的电脑操作系统环境依赖较大 2)B/S 架构:即browser 和 server, 浏览器端和服务器端架构, 2.IP地址: ip地址是一个32位二进制数,通常被分割为4个8位二进制数(就是4个字节).ip地址通常用'点分十进制'表示, 如:100.4.5.6, 每一位都是0-255之间的十进制整数. 转为二进