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