java 网络编程基础 InetAddress类;URLDecoder和URLEncoder;URL和URLConnection;多线程下载文件示例
- IPv4使用32个二进制位在网络上创建单个唯一地址。IPv4地址由四个数字表示,用点分隔。每个数字都是十进制(以10为基底)表示的八位二进制(以2为基底)数字,例如:216.27.61.137。
- IPv6使用128个二进制位在网络上创建一个唯一地址。IPv6地址由八组十六进制(以16为基数)数字表示,这些数字由冒号分隔,如2001:cdba:0000:0000:0000:0000:0000:3257:9652所示。为了节省空间,通常省略包含所有零的数字组,留下冒号分隔符来标记空白(如2001:cdba::3257:9652)。
InetAddress
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException; /**
* @ClassName InetAddressExample
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/5/9.
*/
public class InetAddressExample {
public static void main(String[] args) throws IOException {
/**
* 创建InetAddress 实例getByName静态方法
*/
InetAddress ksyunAddr = InetAddress.getByName("www.ksyun.com");
/**
* 获取IP地址字符串
*/
System.out.println(ksyunAddr.getHostAddress());
/**
* 判断地址是否可达:isReachable
*/
System.out.println(ksyunAddr.isReachable(2000));
/**
* 获取本机IP InetAddress.getLocalHost()
*/
InetAddress localIPObj = InetAddress.getLocalHost();
System.out.println(localIPObj.getHostAddress());
//
//指定IP地址创建 InetAddress对象
InetAddress localIp = InetAddress.getByAddress(new byte[]{127, 0, 0, 1});
}
}
URLDecoder和URLEncoder
public class UrlEncodeTest {
public static void main(String[] args) throws UnsupportedEncodingException {
String url = "https://www.baidu.com/狗逼/";
//转码
String encodeUrl = URLEncoder.encode(url,"utf-8");
System.out.println(encodeUrl); //https%3A%2F%2Fwww.baidu.com%2F%E7%8B%97%E9%80%BC%2F
//解码
String str = URLDecoder.decode(encodeUrl,"utf-8");
System.out.println(str);//https://www.baidu.com/狗逼/ }
}
URL和URLConnection
- String getFile(): 获取该URL资源名。
- String getHost(): 获取URL的主机名
- String getPath(): 获取该URL的路径部分
- int getPort(): 获取URL的端口号。
- String getProtocol(): 获取该URL的协议名称
- String getQuery() 获取该 URL 宇符串部分。
- URLConnection openConnection(): 返回一个URLConnection它代表了与该URL 所引用的远对象的连接。
- InputStream openStream() 打开与此URL连接,并返回一个用于读取该URL资源的 InputStream
多线程下载文件示例:
知识点:
- URL类openConnection() 所引用的远对象的连接; 对象的getContentLength方法获取响应头文件字节长度
- URL类openStream() 打开与此URL连接,并返回一个用于读取该URL资源的 InputStream
- RandomAccessFile类创建文件、预置文件大小、从任意位置读写文件
- 线程池:Executors.newCachedThreadPool() 获取ExecutorService线程池对象,submit 提交任务
- 线程池任务类实现 Runnable 接口,重写run() 方法定义任务细节。
设计思路:
- 获取到文件大小,设置线程数,计算每个线程下载文件的初始字节数和下载(保存)字节数,每个线程从网络get到的字节覆盖写入到本地预置文件的对应字节位置内。
代码示例(Range版):
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* @ClassName ThreadPoolMultiDownLoad
* @projectName: object1
* @author: Zhangmingda
* @description: 使用多线程线程池方式下载文件
* date: 2021/5/9.
*/
public class ThreadPoolMultiDownLoad {
/**
* 要下文件的url地址
*/
private String urlString;
/**
* 线程数
*/
private int threadNum;
/**
* 保存文件的目录
*/
private String saveDir;
/**
* 文件的大小
*/
private int fileSize;
/**
* 线程池
*/
private static ExecutorService threadPool = null; /**
* 下载类构造方法
* @param urlString 文件地址
* @param threadNum 线程数设置
* @param saveDir 本地文件保存目录
*/
public ThreadPoolMultiDownLoad(String urlString, int threadNum, String saveDir) {
this.urlString = urlString;
this.threadNum = threadNum;
this.saveDir = saveDir;
}
/**
* 创建线程池实例的方法,确保线程池为单例(多线程同时运行时使用同一个实例)
*/
private static ExecutorService getThreadPool(){
if (threadPool == null){
synchronized (ThreadPoolMultiDownLoad.class){
if (threadPool == null){
threadPool = Executors.newCachedThreadPool();
}
}
}
return threadPool;
}
/**
* 获取文件大小方法
*/
private int getFileSize(URL url) throws IOException {
return url.openConnection().getContentLength();
}
/**
* 并发用分块下载写入的类
*/
private class DownPart implements Runnable {
private int startByte;
private int threadDownSize;
private RandomAccessFile accessFile;
private URL url; /** 本线程运行所需担心
* @param startByte 下载起始字节
* @param threadDownSize 本线程下载字节量
* @param accessFile 本地写入文件
*/
public DownPart(int startByte, int threadDownSize, RandomAccessFile accessFile,URL url) {
this.startByte = startByte;
this.threadDownSize = threadDownSize;
this.accessFile = accessFile;
this.url = url;
}
//本线程运行方法
@Override
public void run() {
int readcount = 0;
InputStream inputStream = null;
//打开http输入流
try {
URLConnection conn = this.url.openConnection();
/**
* 设置每个请求字节范围
*/
conn.setRequestProperty("Range","bytes=" + startByte + "-" + (startByte + threadDownSize));
inputStream = conn.getInputStream();
// //跳过非本线程需要下载的字节
// inputStream.skip(startByte);
/**
* 将本线程需要下载的字节写到本地文件中
*/
byte[] buffer = new byte[10240];
int len = 0;
while (readcount < this.threadDownSize && (len = inputStream.read(buffer)) != -1 ){
accessFile.write(buffer,0,len);
readcount += len;
}
System.out.println(Thread.currentThread().getName() + "下载写入了" + readcount + "字节的数据" );
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (inputStream != null){inputStream.close(); }
if (accessFile != null){accessFile.close();} } catch (IOException e) {
e.printStackTrace();
}
} }
}
/**
* 下载文件方法
*/
public void download() throws IOException {
/**
* URL构造
*/
URL url = new URL(this.urlString);
/**
* 文件大小获取
*/
this.fileSize = getFileSize(url);
/**
* 每个线程下载的文件大小:由于fileSize总大小除以线程数量后,得出的小数部分会省略,所以每个线程多下载一字节
*/
int threadDownSize = this.threadNum == 1 ? this.fileSize : (this.fileSize / this.threadNum + 1);
/**
* 获取文件名
*/
String[] strings = this.urlString.split("/");
String fileName = strings[strings.length-1];
/**
* 本地预创建文件并预置文件大小
*/
String saveFilePath = this.saveDir + "/" + fileName;
System.out.println(saveFilePath);
RandomAccessFile accessFile = new RandomAccessFile(saveFilePath,"rw");
accessFile.setLength(this.fileSize);
accessFile.close();
/**
* 循环启动线程,分块写入到文件
*/
url = new URL(urlString);
for (int i=0; i<this.threadNum; i++){
//文件起始写入的位置
int startByte = i * threadDownSize;
//打开文件将文件指针移到该线程应该覆盖写入本地文件字节位置
RandomAccessFile randomAccessFile = new RandomAccessFile(saveFilePath,"rw");
randomAccessFile.seek(startByte); getThreadPool().submit(new DownPart(startByte,threadDownSize,randomAccessFile,url));
}
getThreadPool().shutdown();
} /**
* @param args
*/
public static void main(String[] args) throws IOException {
String ks3utilUrl = "https://ks3-cn-beijing.ksyun.com/ks3-import/KS3-import-tool-2.1.4-dist.zip";
new ThreadPoolMultiDownLoad(ks3utilUrl,4,"网络编程/src").download();
}
}
java 网络编程基础 InetAddress类;URLDecoder和URLEncoder;URL和URLConnection;多线程下载文件示例的更多相关文章
- Java 网络编程:必知必会的 URL 和 URLConnection
java.net.URL 类将 URL 地址进行了封装,并提供了解析 URL 地址的基本方法,比如获取 URL 的主机名和端口号.java.net.URLConnection 则代表了应用程序和 UR ...
- Java网络编程和NIO详解开篇:Java网络编程基础
Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为 ...
- Java网络编程基础(Netty预备知识)
今天在家休息,闲来无事,写篇博客,陶冶下情操~~~ =================我是分割线================ 最近在重新学习Java网络编程基础,以便后续进行Netty的学习. 整 ...
- java网络编程基础——网络基础
java网络编程 网络编程基础 1.常用的网络拓扑结构: 星型网络.总线网络.环线网络.树形网络.星型环线网络 2.通信协议的组成 通信协议通常由3部分组成: 语义部分:用于决定通信双方对话类型 语法 ...
- 【Java基础】Java网络编程基础知识
什么是网络编程 网络编程是通过使用套接字来达到进程间通信目的,那什么是套接字呢?其实套接字是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的 ...
- java网络编程基础——基本网络支持
基本网络支持 java.net包主要为网络编程提供支持. 1.InetAddress InetAddress类代表IP地址,还有两个子类:Inet4Address.Inet6Address. pack ...
- java网络编程基础
前言 通过网络进行数据传输时,一般使用TCP/UDP进行数据传输.但是两个的区别就是TCP可靠,UDP不可靠.两个的共同之处就是都需要建立socket套接字,将IP地址和端口port进行绑定.但是服务 ...
- java网络编程基础——TCP网络编程一
基于TCP协议的网络编程 TCP/IP协议是一种可靠的网络协议,它的通信的两端各自建立一个Socket,从而在通信的两端之间形成网络虚拟链路. Java使用Socket对象来代表两端的通信端口,并通过 ...
- JAVA网络编程基础知识
网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯.网络编程中有两个主要的问题,一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输.在TCP/IP协 ...
随机推荐
- Apache ShardingSphere 5.0.0 内核优化及升级指南
经过近两年时间的优化和打磨,Apache ShardingSphere 5.0.0 GA 版终于在本月正式发布,相比于 4.1.1 GA 版,5.0.0 GA 版在内核层面进行了大量的优化.首先,基于 ...
- Nginx大厂面试需要掌握多少v1.21.3
概述 **本人博客网站 **IT小神 www.itxiaoshen.com Nginx官网 最新版本为1.21.3 Nginx (engine x) 是一个开源的.高性能的HTTP和反向代理web服务 ...
- Atcoder Grand Contest 001 F - Wide Swap(拓扑排序)
Atcoder 题面传送门 & 洛谷题面传送门 咦?鸽子 tzc 来补题解了?奇迹奇迹( 首先考虑什么样的排列可以得到.我们考虑 \(p\) 的逆排列 \(q\),那么每次操作的过程从逆排列的 ...
- Codeforces 997E - Good Subsegments(线段树维护最小值个数+历史最小值个数之和)
Portal 题意: 给出排列 \(p_1,p_2,p_3,\dots,p_n\),定义一个区间 \([l,r]\) 是好的当且仅当 \(p_l,p_{l+1},p_{l+2},\dots,p_r\) ...
- 【基因组组装】HiC挂载Juicebox纠错补充
目录 1. 主要纠错类型 misjoins translocations inversions chromosome boundaries 2. 其他有用操作 撤销与反撤销 移到边角料 1. 主要纠错 ...
- Python基础之流程控制while循环
目录 1. 语法 2. while+break 3. while+continue 4. while+else 1. 语法 最简单的while循环如下: ''' while <条件>: & ...
- Nginx编译参数详细介绍
/configure --help --help 显示本提示信息 --prefix=PATH 设定安装目录 --sbin-path=PATH 设定程序文件目录 --conf-path=PATH 设定配 ...
- javaSE高级篇2 — 流技术 — 更新完毕
1.先认识一个类----File类 前言:IO相关的一些常识 I / O----输入输出 I 输入 input 0 输出 output I / o 按数据的流动方向来分- ...
- 疯了吧!这帮人居然用 Go 写“前端”?(二)
作者 | 郑嘉涛(羣青) 来源|尔达 Erda 公众号 前言 上篇我们讲了故事发生的背景,也简单阐述了组件及协议的设想: 一.丰富的通用组件库. 二.组件渲染能力,将业务组件渲染成通用组件 ...
- day07 Linux配置修改
day07 Linux配置修改 昨日回顾 1.系统目录 /etc :系统配置目录 /bin-> /usr/bin :保存常用命令的目录 /root :超级管理员目录 /home :普通管理员目录 ...