java核心学习(二十九) 基本网络支持

Posted The_shy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java核心学习(二十九) 基本网络支持相关的知识,希望对你有一定的参考价值。

一、InetAddress

  java提供了InetAddress代表IP地址,它有两个子类Inet4Address和Inet6Address,分别代表了IPV4和IPV6地址。

  这个类没有构造器,而是使用两个静态工厂方法来获得InetAddress实例

   getByName(String host);

   getByAddress(byte[] addr);

  它的四个主要实例方法

    String getCanonicalHostName();取得该IP地址的全限定域名

    String getHostAddress();取得IP地址

    String getHostName();取得该IP地址的主机名

    Boolean isReachable();判断该IP地址是否可达,可以传入一个等待时长作为参数

二、URLDecoder 和 URLEncoder

  这两个类用于完成普通字符串与application/x-www-form-urlencoded MIME 字符串之间的相互转换。

  什么是application/x-www-form-urlencoded MIME 字符串?

   当URL地址里包含非西欧字符的字符串时,系统会将这些非西欧字符转化为特殊的字符串,所以后台接受到的URL需要经过解码转换为普通字符串,这就用到了URLDecoder;当程序发送请求时,需要使用URLEncoder将URL普通字符串编码转换为特殊字符串。

  解码和编码分别使用这两个类的静态方法decode(String s , String enc) 、encode(String s ,String enc)来完成。enc为字符集。

三、URL、URLConnection和URLPermission

  这三个应该属于应用层的API

  下面实现一个多线程下载的工具类来试用一下这个API

  参考 HTTP请求头详解

package net;

import java.io.File;
import java.io.FileReader;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;


public class DownUtil {
    private String path;  //下载资源的路径
    private String targetFile;  //
    private int threadNum;
    private DownThread[] threads;
    private int filesize;
    private final String infoFileSuffix = "INI.txt";

    public DownUtil(String path, String targetFile, int threadNum) {
        this.path = path;
        this.targetFile = targetFile;
        this.threadNum = threadNum;
    }

    public DownUtil(String path, String targetFile) {
        this.path = path;
        this.targetFile = targetFile;
        this.threadNum = Runtime.getRuntime().availableProcessors();//默认开启当前机器CPU数量的线程
    }
    public void download() throws Exception{
        //建立http请求取得文件大小
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Accept","*/*");
        conn.setRequestProperty("Accept-Language","zh-CN");
        conn.setRequestProperty("Charset","UTF-8");
        conn.setRequestProperty("Connection","Keep-Alive");
        filesize = conn.getContentLength(); //取得文件大小
        conn.disconnect();
        //将下载任务分配给每个线程
        int currentPartSize = filesize / threadNum + 1; //每个线程负责的文件块的大小
        Path path = Paths.get(targetFile+infoFileSuffix);
        if(Files.exists(path)){

            //读取文件内容继续下载
            List<String> allLine = Files.readAllLines(path, Charset.forName("UTF-8"));
            for(int i = 0 ; i < threadNum ; i++){
                int startPos = i * currentPartSize;
                RandomAccessFile currentPart = new RandomAccessFile(targetFile,"rw");
                currentPart.seek(startPos);
                threads[i] = new DownThread(startPos,currentPartSize,currentPart,Integer.parseInt(allLine.get(i).toString()));
                threads[i].start();
            }

        }else {
            RandomAccessFile file = new RandomAccessFile(targetFile,"rw");
            file.setLength(filesize);
            file.close();
            List<String> infoStrings = new ArrayList<>();
            for(int i = 0 ; i < threadNum ; i++){
                infoStrings.add("0");
            }
            Files.write(path,infoStrings,Charset.forName("UTF-8"));
            for(int i = 0 ; i < threadNum ; i++){
                int startPos = i * currentPartSize;
                RandomAccessFile currentPart = new RandomAccessFile(targetFile,"rw");
                currentPart.seek(startPos);
                threads[i] = new DownThread(startPos,currentPartSize,currentPart);
                threads[i].start();
            }
            //重新写入文件
        }
    }

    private class DownThread extends Thread{

        private int startPos; //当前线程开始下载的位置
        private int currentPartSize;    //当前线程负责下载的大小
        private RandomAccessFile currntPart;  //当前线程需要下载的文件类
        public int length; //已下载的字节数,如果要实现断点下载,可以吧这个数据存在硬盘上,即存在文件里
        private final String acceptString = "*/*";
        private final String charSetString = "UTF-8";
        private final String acceptLanguageString = "zh-CN";


        public DownThread(int startPos, int currentPartSize, RandomAccessFile currntPart,int length) {
            this.startPos = startPos;
            this.currentPartSize = currentPartSize;
            this.currntPart = currntPart;
            this.length = length;
        }

        public DownThread(int startPos, int currentPartSize, RandomAccessFile currrntPart){
            this.startPos = startPos;
            this.currentPartSize = currentPartSize;
            this.currntPart = currrntPart;
            this.length = 0;
        }

        @Override
        public void run() {
            try {
                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(5000);
                conn.setRequestMethod("GET");
                conn.setRequestProperty("Accept",acceptString);
                conn.setRequestProperty("Charset",charSetString);
                conn.setRequestProperty("Accept-Language",acceptLanguageString);
                conn.setRequestProperty("Range","bytes=" + (startPos + length) + "-" + (startPos + currentPartSize - 1));
                InputStream inputStream = conn.getInputStream();

                byte[] buffer = new byte[1024];
                int hasRead = 0; //一次循环读取的字节数
                while (length < currentPartSize && (hasRead = inputStream.read(buffer)) != -1){
                    currntPart.write(buffer,0,hasRead);
                    length += hasRead;
                }
                currntPart.close();
                inputStream.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

  以上代码还可以增加断点续传下载功能,这段代码基本上展示了URL和URLconniction(抽象类)这两个类的用法

  而URLPermission则是java8新增的工具类,用于管理HttpURLConniction的权限问题,如果不重复造轮子基本用不到,即是要用到也在用到的时候查看文档即可(java的类太多了)。

  

以上是关于java核心学习(二十九) 基本网络支持的主要内容,如果未能解决你的问题,请参考以下文章

大厂Java核心面试知识点整理,二十九个专题任你挑,美滋滋~

深度学习核心技术精讲100篇(二十九)-基于内容和上下文的音乐推荐

Linux学习总结(二十九)系统日志

Python学习日记(二十九) 网络编程

“全栈2019”Java第二十九章:数组详解(中篇)

FreeSql (二十九)Lambda 表达式