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协 ...
随机推荐
- jpa生成uuid
使用jpa可以生成uuid,但是我直接添加数据没有id值会报错,只在程序中有效,如果直接修改数据库需要手动填写,另外长度不要乱填 ,之前填了200,找了半天才找到原因. package com.jav ...
- centos与ubuntu安装及相关问题解答
1.按系列罗列Linux的发行版,并描述不同发行版之间的联系与区别. 答:Linus的发行版本有slackware,debian,redhat,Alpine,ArchLinux,Gentoo,LFS, ...
- Codeforces 1466G - Song of the Sirens(哈希)
Codeforces 题面传送门 & 洛谷题面传送门 事实证明,有的难度评分不算很高.涉及的知识点不算很难的题目也能出得非常神仙 首先考虑如何暴力求答案.注意到一个文本串 \(T\) 在 \( ...
- 【R】clusterProfiler的GO/KEGG富集分析用法小结
前言 关于clusterProfiler这个R包就不介绍了,网红教授宣传得很成功,功能也比较强大,主要是做GO和KEGG的功能富集及其可视化.简单总结下用法,以后用时可直接找来用. 首先考虑一个问题: ...
- MicrosoftPowerBI—2019-nCov 新型冠状病毒肺炎多功能动态看板
https://app.powerbi.cn/view?r=eyJrIjoiNmE0ZDU0MGItOTFjYy00MWYyLWFmZjMtMThkM2EwMzg5YjgyIiwidCI6ImQxNj ...
- linux 线程函数小结
由于主线程已经开始跑了,次线程还在使用串口打印需要一点时间,因此打印的都是重复的. #include "pthread.h" #include "stdio.h" ...
- MybatisPlus的CRUD及拓展
创建一个简单的MybatisPlus项目在上一篇博客:MybatisPlus入门程序 一.CRUD 1. select 1.1 查找全部用户 //查 @Test public void select( ...
- X-MagicBox-820的luatOS之路连载系列6
继上次用Qt实现了显示地图和MQTT通信之后(X-MagicBox-820的luatOS之路连载系列5),说是要研究下地图的开放接口,也看了标记点和线的方法(地图上自定义标记点和轨迹线的实现).这次就 ...
- 学习java的第二十天
一.今日收获 1.java完全学习手册第三章算法的3.2排序,比较了跟c语言排序上的不同 2.观看哔哩哔哩上的教学视频 二.今日问题 1.快速排序法的运行调试多次 2.哔哩哔哩教学视频的一些术语不太理 ...
- add more
# -*- coding: utf-8 -*- print('123', 123) print(type('123'), type(123)) # string, integer /ˈintidʒə/ ...