Java开发实战1200例(第二卷)学习笔记—网络应用基础

第10章网络应用基础

10.1 网络地址解析

实例297:获取本地主机的IP地址

  • 通过InetAddress类的getLocalHost()方法获得本地主机的InetAddress对象
  • 调用该对象的getHostAddress()方法获得本地主机的IP地址。
    主要代码如下:
//创建本地主机的InetAddress对象
InetAddress inetAddr=InetAddress.getLocalHost();
//获得本地主机的IP地址
String ip=inetAddr.getHostAddress();

以下摘录自Jdk 1.8谷歌翻译

public static InetAddress getLocalHost() throws
UnknownHostException
返回本地主机的地址。
这是通过从系统检索主机的名称,然后将该名称解析为InetAddress 。 注意:解决的地址可能会缓存一段时间。
如果有一个安全管理器,它的checkConnect方法被调用本地主机名, -1作为参数来查看是否允许该操作。
如果不允许操作,则返回表示环回地址的InetAddress。 结果 :本地主机的地址。 异常 :UnknownHostException
- 如果本地主机名无法解析成地址。 public String getHostAddress() 返回文本显示中的IP地址字符串。 结果 :原始IP地址为字符串格式。 从以下版本开始: JDK1.0.2

实例298:获取本地主机的域名和主机名

  • 通过InetAddress类的getLocalHost()方法获得本地主机的InetAddress对象
  • 调用getHostName()方法获得本地主机的名
  • 调用getCanonicaHostName()方法获得本地主机的域名
    主要代码如下:
//创建本地主机的InetAddress对象
InetAddress inetAddr=InetAddress.getLocalHost();
//获取本地主机的域名
String canonical=inetAddr.getCanonicalHostName();
//获取本地主机的主机名
String host=inetAddr.getHostName();

注意:当获得本地主机的域名和主机名时,如果本地主机没有域名,则显示的域名和主机名重名;如果本地主机有域名,就会显示对应的域名。
以下摘录自Jdk 1.8谷歌翻译

public String getCanonicalHostName()
获取此IP地址的完全限定域名。
最好的方法,意味着我们可能无法返回FQDN取决于底层的
系统配置。
如果有安全管理员,则该方法首先使用主机名称调用其checkConnect方法,并-1作为参数,以查看主叫代码是否被允许知道该IP地址的主机名,即连接到主机。
如果不允许操作,它将返回IP地址的文本表示。 结果 :该IP地址的完全限定域名,或者安全检查不允许操作时,该IP地址的文本表示。
从以下版本开始: 1.4

public String getHostName() 获取此IP地址的主机名。
如果此InetAddress是使用主机名创建的,则该主机名将被记住并返回;
否则,将执行反向名称查找,并将基于系统配置的名称查找服务返回结果。
如果有一个安全管理器,它的checkConnect方法首先被调用与主机名和-1作为参数,看看是否允许操作。
如果不允许操作,它将返回IP地址的文本表示。 结果 :该IP地址的主机名,或者安全检查不允许操作时,IP地址的文本表示。

实例299:通过域名获得IP地址

  • 通过InetAddress类的getByName()方法,获得网络中指定域名的InetAddress对象
  • 调用该对象的getHostAddress()方法,获得具有该域名的主机IP地址
    主要代码如下:
//获得输入的域名
String domain=tf_domain.getText();
//创建InetAddress对象
InetAddress inetAddr=InetAddress.getByName(domain);
//获得IP地址
String ip=inetAddr.getHostAddress();

以下摘录自Jdk 1.8谷歌翻译

public static InetAddress getByName(String host) throws UnknownHostException
主机名称可以是机器名称,例如“ java.sun.com ”或其IP地址的文本表示。 如果提供了文字IP地址,则只会检查地址格式的有效性。
为host在字面的IPv6地址指定的,无论是在RFC 2732或RFC中定义的2373字面IPv6地址格式中定义的形式被接受。
还支持IPv6作用域地址。 见here对IPv6的范围地址的描述。
如果主机是null则返回一个InetAddress回送接口地址的InetAddress。
参数:host - 指定的主机,或 null 。
结果:给定主机名的IP地址。
异常:UnknownHostException -
如果没有找到 host IP地址,或者是否为全局IPv6地址指定了scope_id。
SecurityException -
如果安全管理器存在,并且其checkConnect方法不允许该操作

实例300:通过IP地址获得域名和主机名

  • 将IP地址转换成字节数组
  • 通过InetAddress类的getByAddress()方法,获得主机中具有指定IP地址的InetAddress对象
  • 调用该对象的getCanonicalHostName()方法,获得对应的域名
  • 通过getHostName()方法,获得对应的主机名。
    主要代码如下:
//将IP地址转换为字节数组
String ip=tf_ip.getText();//输入IP地址字符串
String[] ipStr=ip.split("[.]");//转换成字符数组
byte[] ipBytes=new byte[4];
for(int i=0;i<4;i++){
    int m=Integer.parseInt(ipStr[i])//转换成整数
    byte b=(byte)(m&0xff);//转换为字节
    ipBytes[i]=b;//赋值给字节数组
}
//创建本地主机的InetAddress对象
InetAddress inetAddr=InetAddress.getLocalHost();
//获取本地主机的域名
String canonical=inetAddr.getCanonicalHostName();
//获取本地主机的主机名
String host=inetAddr.getHostName();

实例301 获得内网的所有IP地址

  • 获得本机IP地址所属的网段
  • ping网络中的IP地址
  • 通过输入流对象读取所ping结果,并判断是否为内网的IP地址
    主要代码如下:
//获取本机IP地址所属的网段
//获得本机的InetAddress对象
InetAddress host=InetAddress.getLocalHost();
//获得本机的IP地址
String hostAddress=host.getHostAddress();
//获得IP地址中最后一个点的位置
int pos=hostAddress.lastIndexOf(".");
//对本机的IP地址进行截取,获得网段
String wd=hostAddress.substring(0,pos+1);
//对局域网的IP地址进行遍历
for(int i=1;i<=255;i++){
    String ip=wd+i;
    PingIpThread thread=new PingIpThread(ip);
    thread.start();
}
//获得集合中键的Set视图
Set<String> set=pingMap.keySet();
Iterator<String> it=set.itrator();//获得迭代器对象
while(it.hasNext()){
    String key=it.next();
    String value=pingMap.get(key);
    if(value.equals("true")){
        ta_allIp.append(key+"\n");
}
}
//ping网络中的IP地址,通过输入流对象读取所Ping结果,并判断是否为内网的IP地址
//获得所ping的IP进程,-w 280 是等待每次回复的超时时间,-n 1 是要发送的回显请求数
Process process=Runtime.getRuntime().exec("ping"+ip+"-w 280 -n 1");
InputStream is=process.getInputStream();//获得进程的输入流对象
InputStream is=process.getInputStreamReader(is);//创建InputStreamReader对象
BufferReader in=new BufferedReader(isr);//创建缓冲字符流对象
String line=in.readLine();//读取信息
while(line!=null){
    if(line!=null&&!line.equals("")){
        if(line.substring(0,2).equals("来自")
        ||(line.length()>10&&line.substring(0,10)
                .equals("Reply from"))){//判断是ping通过的IP地址
        pingMap.put(ip,"true");//向集合中添加IP地址
}
}
line=in.readLine();//再读取信息
}

10.2网络资源管理

实例302:获取网络资源的大小

-通过URLContentLength()方法获得网络资源大小
-在文本框中显示

//获得网络资源大小
public long netSourcesSize(String sUrl) throws Exception{
    URL url=new URL(sUrl);//创建URL对象
    URLConnection urlConn=url.openConnection();//获得网络连接对象
    urlConn.connect();//dakai url引用资源的通信链接
    return urlConn.getContentLength();//以字节为单位返回资源的大小
}
//在文本框中显示
String address=textFile.getText().trim();//获得输入的网址
long len=netSourceSize(address);//调用方法获取网络资源的大小
textFile_1.setText(String.valueOf(len)+"字节");//在文本框中显示网络资源的大小

实例303:解析网页中的内容

-通过URLConnection类的getInputStream()方法获得网页资源的输入流对象
-从该输入流中读取信息

//解析网页内容
public Collection<String>  getURLCollection(String urlString){
    URL url=null;//声明URL
    URLConnection<String> urlCollection=new ArrayList<String>();//创建集合对象
    try{
        url=new URl(urlString);//创建URL对象
        conn=url.openConnection();//获得连接对象
        conn.connect();//打开到url引用资源的通信连接
        InputStream is=conn.getInputStrean();//获取流对象
        InputStreamReader in=new INputStreanReader(is,"UTF-8");//转换为字符流
        BufferedReader br=new BufferedReader(in);//创建缓冲流对象
        String nextLine=br.readLine();//读取信息,解析网页
        while(nextLine!=null){
            urlCollection.add(nextLine);//解析网页的全部内容,添加到集合中
            nextLine=br.readLine();//读取信息,解析网页
}
}catch(Exception ex){
    ex.printStackTrance();
}
return urlCollection;
}
//输出信息
String address=tf_address.getText().trim();//获得输入的网址
Collection urlCollection=getURLCollection(address);//调用方法,获得网页内容的集合对象
Iterator it=urlCollection.iterator();//获得集合的迭代器对象
while(it.hasNext()){
ta_contet.append((String)it.next()+"\n");//在文本域中显示解析的内容
}

实例304:网络资源的单线程下载

-利用URLConnection对象的getInputStream()方法,获得网络资源的输入流对象
-使用FileOutputStream类创建输出流对象,然后使用该类的write()方法,将从输入流获得的网络资源保存到磁盘上,实现网络资源的单线程下载。

//定义download()方法,用于根据参数urlAddr指定的地址,完成网络资源的单线程下载
public void download(String urlAddr){//从指定网址下载文件
    try{
        URL url=new URL(urlAddr);//创建URL对象
        URLConnection urlConn=url.openConnection();//获得连接对象
        urlConn.connect();//打开到url引用资源的通信链接
        InputStream in=urlConn.getInputStream();//获得输入流对象
        int pos=filePath.lastIndexOf("/");//获得路径中最后一个斜杠的位置
        String fileName=filePath.substring(pos+1);//截取文件名
        FileOutputStream out=new FileOutStream("C:/"+fileName);//创建输出流对象
        byte[] bytes=new byte[1024];//声明存放下载内容的字节数组
        int len=in.read(bytes);//从输入流中读取内容
        while(len!=-1){
            out.write(bytes,0,len);//将读取的内容写到输出流
            len=in.read(bytes);//继续从输入流中读取内容
        }
        out.close();//关闭输出流
        in.close();//关闭输入流
        JOptionPane.showMessageDialog(null,"下载完毕");
}catch(Exception e){
    e.printStackTrance();
}
}

注意:在下载网络资源时,需要及时关闭IO流,因为每个IO流都会占用较多的系统资源,并且IO流并不能被垃圾回收机制回收,当下载网络资源的用户较多时,就会造成不必要的资源浪费,甚至会使系统崩溃。

实例305:网络资源的多线程下载

-创建线程类
-使用RandomAccessFile类的seek()方法定位下一个写入点
-通过write()方法写入文件

//实现通过线程类DownMultiThread下载网络资源
public void download(String url, String dest, int threadNum)
            throws Exception {
        URL downURL = new URL(url);// 创建网络资源的URL
        HttpURLConnection conn = (HttpURLConnection) downURL.openConnection();// 打开网络边接
        long fileLength = -1;// 用于存储文件长度的变量
        int stateFlagCode = conn.getResponseCode();// 获得连接状态标记代码
        if (stateFlagCode == 200) {// 网络连接正常
            fileLength = conn.getContentLength();// 获得文件的长度
            conn.disconnect();// 取消网络连接
        }
        if (fileLength > 0) {
            long byteCounts = fileLength / threadNum + 1;// 计算每个线程的字节数
            File file = new File(dest);// 创建目标文件的File对象
            int i = 0;
            while (i < threadNum) {
                long startPosition = byteCounts * i;// 定义开始位置
                long endPosition = byteCounts * (i + 1);// 定义结束位置
                if (i == threadNum - 1) {
                    DownMultiThread fileThread = new DownMultiThread(url, file,
                            startPosition, 0);// 创建DownMultiThread线程的实例
                    new Thread(fileThread).start();// 启动线程对象
                } else {
                    DownMultiThread fileThread = new DownMultiThread(url, file,
                            startPosition, endPosition);// 创建DownMultiThread线程的实例
                    new Thread(fileThread).start();// 启动线程对象
                }
                i++;
            }
            JOptionPane.showMessageDialog(null, "完成网络资源的下载。");
        }
    }
    //创建一个实现Runnable接口的线程类DownMultiThread,用于实现网络资源的下载
    public class DownMultiThread implements Runnable{
    private String sUrl = "";// 网络资源地址
    private File desFile;// 需要写入的目标文件对象
    private long startPos;// 写入的开始位置
    private long endPos;// 写入的结束位置
    public DownMultiThread(String sUrl,File desFile,long startPos,long endPos) {
        this.sUrl = sUrl;
        this.desFile = desFile;
        this.startPos = startPos;
        this.endPos = endPos;
    }
    @Override
    public void run() {
        try {
            URL url = new URL(sUrl);// 创建下载资源的URL对象
            HttpURLConnection conn = (HttpURLConnection)url.openConnection();// 打开连接对象
            conn.setRequestProperty("User-Agent", "NetFox");// 设置请求属性
            String rangeProperty = "bytes="+startPos+"-";// 定义范围属性
            if (endPos > 0){
                rangeProperty = "bytes="+startPos+"-" + endPos;// 调整范围属性的值
            }
            conn.setRequestProperty("RANGE", rangeProperty);// 指定范围属性
            RandomAccessFile out = new RandomAccessFile(desFile, "rw");// 创建可读写的流对象
            out.seek(startPos);// 指定读写的开始标记
            InputStream in = conn.getInputStream();// 获得网络资源的输入流对象
            BufferedInputStream bin = new BufferedInputStream(in);// 创建输入缓冲流对象
            byte[] buff = new byte[2048];// 创建字节数组
            int len = -1;// 声明存放读取字节数的变量
            len=bin.read(buff);// 读取到内容并添加到字节数组
            while (len!=-1){
                out.write(buff,0,len);// 写入磁盘文件
                len=bin.read(buff);// 读取到内容并添加到字节数组
            }
            out.close();// 关闭流
            bin.close();// 关闭流
            conn.disconnect();// 断开连接
        }catch(Exception ex) {
            JOptionPane.showMessageDialog(null, ex.getMessage());
        }
    }
}

实例306下载网络资源的断点续传

本实例主要是通过设置请求参数RANGE实现的,通过该参数,可以指定下载网络资源的字节区间,从而实现每次下载部分网络资源的功能。
全部代码如下:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

@SuppressWarnings("serial")
public class BreakPointSuperveneFrame extends JFrame {
    private JTextField tf_totalLength;
    private JTextField tf_residuaryLength;
    private JTextField tf_readToPos;
    private JTextField tf_address;
    private JTextField tf_endPos;
    private JTextField tf_startPos;
    private String urlAddress = "";// 用于存储网络资源的地址
    private long totalLength = 0;// 存储网络资源的大小,以字节为单位
    private long readToPos = 0;// 存储上次读取到的位置
    private long residuaryLength = 0;// 存储未读内容的大小

    /**
     * Launch the application
     * 
     * @param args
     */
    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    BreakPointSuperveneFrame frame = new BreakPointSuperveneFrame();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame
     */
    public BreakPointSuperveneFrame() {
        super();
        getContentPane().setLayout(null);
        setTitle("下载网络资源的断点续传");
        setBounds(100, 100, 514, 238);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        tf_startPos = new JTextField();
        tf_startPos.setBounds(80, 165, 113, 22);
        getContentPane().add(tf_startPos);

        final JLabel label = new JLabel();
        label.setText("起始位置:");
        label.setBounds(10, 167, 74, 18);
        getContentPane().add(label);

        final JLabel label_1 = new JLabel();
        label_1.setText("结束位置:");
        label_1.setBounds(199, 167, 74, 18);
        getContentPane().add(label_1);

        tf_endPos = new JTextField();
        tf_endPos.setBounds(267, 165, 117, 22);
        getContentPane().add(tf_endPos);

        final JLabel label_2 = new JLabel();
        label_2.setText("网络资源的地址:");
        label_2.setBounds(10, 52, 113, 18);
        getContentPane().add(label_2);

        tf_address = new JTextField();
        tf_address.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                try {
                    urlAddress = tf_address.getText().trim();
                    URL url = new URL(urlAddress);// 获得网络资源的URL
                    HttpURLConnection connection = (HttpURLConnection) url
                            .openConnection();// 获得连接对象
                    connection.connect();// 连接网络资源
                    totalLength = connection.getContentLength();// 获得网络资源的长度
                    connection.disconnect();// 断开连接
                    tf_totalLength.setText(String.valueOf(totalLength));// 显示总长度
                    tf_readToPos.setText("0");// 显示上次读取到的位置
                    residuaryLength = totalLength;// 未读内容为文件总长度
                    tf_residuaryLength.setText(String.valueOf(residuaryLength));// 显示未读内容
                } catch (MalformedURLException e1) {
                    e1.printStackTrace();
                } catch (IOException e2) {
                    e2.printStackTrace();
                }

            }
        });
        tf_address.setBounds(119, 50, 365, 22);
        getContentPane().add(tf_address);

        final JLabel label_3 = new JLabel();
        label_3.setForeground(new Color(0, 0, 255));
        label_3.setFont(new Font("", Font.BOLD, 14));
        label_3.setText("输入网络资源的地址并回车,可以获得网络资源的大小。");
        label_3.setBounds(10, 10, 384, 22);
        getContentPane().add(label_3);

        final JLabel label_4 = new JLabel();
        label_4.setForeground(new Color(128, 0, 0));
        label_4.setText("网络资源的大小为");
        label_4.setBounds(10, 76, 113, 38);
        getContentPane().add(label_4);

        final JLabel label_5 = new JLabel();
        label_5.setText("上次读取到");
        label_5.setBounds(10, 123, 74, 18);
        getContentPane().add(label_5);

        tf_readToPos = new JTextField();
        tf_readToPos.setBounds(80, 121, 113, 22);
        tf_readToPos.setEnabled(false);
        getContentPane().add(tf_readToPos);

        final JLabel label_6 = new JLabel();
        label_6.setText("字节处,还剩");
        label_6.setBounds(202, 123, 87, 18);
        getContentPane().add(label_6);

        tf_residuaryLength = new JTextField();
        tf_residuaryLength.setBounds(285, 120, 117, 22);
        tf_residuaryLength.setEnabled(false);
        getContentPane().add(tf_residuaryLength);

        final JLabel label_7 = new JLabel();
        label_7.setText("字节未读。");
        label_7.setBounds(404, 123, 80, 18);
        getContentPane().add(label_7);

        final JLabel label_4_1 = new JLabel();
        label_4_1.setForeground(new Color(128, 0, 0));
        label_4_1.setText("个字节。");
        label_4_1.setBounds(404, 76, 80, 38);
        getContentPane().add(label_4_1);

        tf_totalLength = new JTextField();
        tf_totalLength.setBounds(119, 84, 283, 22);
        tf_totalLength.setEnabled(false);
        getContentPane().add(tf_totalLength);

        final JButton button = new JButton();
        button.setBounds(395, 162, 89, 28);
        getContentPane().add(button);
        button.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                if (totalLength == 0) {
                    JOptionPane.showMessageDialog(null,
                            "没有网络资源。\n\n请输入正确的网址,然后回车。");
                    return;
                }
                long startPos = 0;// 起始位置
                long endPos = 0;// 结束位置
                try {
                    startPos = Long.parseLong(tf_startPos.getText().trim());// 起始位置
                    endPos = Long.parseLong(tf_endPos.getText().trim());// 结束位置
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(null, "输入的起始位置或结束位置不正确。");
                    return;
                }
                readToPos = endPos;// 记录读取到的位置
                residuaryLength = totalLength - readToPos;// 记录未读内容的大小
                tf_readToPos.setText(String.valueOf(readToPos));// 显示读取到的位置
                tf_residuaryLength.setText(String.valueOf(residuaryLength));// 显示未读字节数
                tf_startPos.setText(String.valueOf(readToPos));// 设置下一个读取点的开始位置
                tf_endPos.setText(String.valueOf(totalLength));// 设置下一个读取点的结束位置
                tf_endPos.requestFocus();// 使结束位置文本框获得焦点
                tf_endPos.selectAll();// 选择结束位置文本框中的全部内容,方便输入结束位置值
                download(startPos, endPos);// 调用方法进行下载
            }
        });
        button.setText("开始下载");
    }

    public void download(long startPosition, long endPosition) {
        try {
            URL url = new URL(urlAddress);// 获得网络资源的URL
            HttpURLConnection connection = (HttpURLConnection) url
                    .openConnection();// 获得连接对象
            connection.setRequestProperty("User-Agent", "NetFox");// 设置请求属性
            String rangeProperty = "bytes=" + startPosition + "-";// 定义请求范围属性
            if (endPosition > 0) {
                rangeProperty += endPosition;// 调整请求范围属性
            }
            connection.setRequestProperty("RANGE", rangeProperty);// 设置请求范围属性
            connection.connect();// 连接网络资源
            InputStream in = connection.getInputStream();// 获得输入流对象
            String file = url.getFile();// 获得文件对象
            String name = file.substring(file.lastIndexOf('/') + 1);// 获得文件名
            FileOutputStream out = new FileOutputStream("c:/" + name, true);// 创建输出流对象,保存下载的资源
            byte[] buff = new byte[2048];// 创建字节数组
            int len = 0;// 定义存储读取内容长度的变量
            len = in.read(buff);// 读取内容
            while (len != -1) {
                out.write(buff, 0, len);// 写入磁盘
                len = in.read(buff);// 读取内容
            }
            out.close();// 关闭流
            in.close();// 关闭流
            connection.disconnect();// 断开连接
            if (readToPos > 0 && readToPos == totalLength) {
                JOptionPane.showMessageDialog(null, "完成网络资源的下载。\n单击“确定”按钮退出程序。");
                System.exit(0);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

参考书籍《Java开发实战1200例》(第二卷)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值