1. 程式人生 > >Java開發實戰1200例(第二卷)學習筆記—網路應用基礎

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例》(第二卷)