zoukankan      html  css  js  c++  java
  • 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 接口与抽象类
    【知了堂学习笔记】java web 简单的登录
    【知了堂学习笔记】java IO流归纳总结
    【知了堂学习笔记】java 自定义异常
    【知了堂学习笔记】java 方法重载与重写的归纳
    编译链接符号重定位流程简述
    项目用到了lua的哪些部分
    lua协程实现简析
    杂乱无章
  • 原文地址:https://www.cnblogs.com/Theshy/p/7650086.html
Copyright © 2011-2022 走看看