下面內容是Java開發內容的高級知識點,須要對Java中的面向對象、IO、多線程、以及網絡相關知識有必定的基礎。(知識永遠都有深度,本章節長期更新內容)html
一、網絡基礎知識java
網絡通訊的條件:一、兩個通訊的端都要有各自的IP地址做爲惟一標識,簡單的來講IP地址用來區分不一樣機器(計算機)。二、語言要相通。三、如何辨別不一樣程序的通訊須要端口號來區別,簡單的來講端口號就是用來標識不一樣的應用程序。
TCP/IP是目前世界上使用最普遍的協議,是以TCP和IP爲基礎的不一樣層次上多個協議的集合,也稱TCP/IP協議族 或 TCP/IP 協議棧。
TCP:Transmission Control Protocol 傳輸控制協議
IP:Internet Protocol 互聯網協議
TCP/IP模型編程
>>IP和端口<<
一、用於區分不一樣應用程序。
二、端口號範圍爲0~65535,其中0~1023爲系統所保留。若是自定義端口號,因此建議用1024以後的端口號。
三、IP地址和端口號組成了所謂的Socket,Socket是網絡上運行程序之間雙向通訊鏈路的終結點,是TCP和UDP的基礎。api
經常使用的端口號須要記一下:http:80 ftp:21 telnet:23數組
——————————Java中的網絡支持—————————
針對網絡通訊的不一樣層次,Java提供的網絡功能有四大類:
>>一、InetAddress:用於標識網絡上的硬件資源
>>二、URL:統一資源定位符 經過URL能夠直接讀取或寫入網絡上的數據
>>三、Socket:使用TCP協議實現網絡通訊的Socket相關的類。
>>四、Datagram:使用UDP協議,將數據保存在數據報中,經過網絡進行通訊。服務器
二、InetAddress類網絡
查看I-net-Address的API文檔,發現沒有構造方法,也就是不能經過new來建立。因此確定有靜態的方法來建立。多線程
1 import java.net.InetAddress; 2 import java.net.UnknownHostException; 3 import java.util.Arrays; 4 5 public class Test1{ 6 public static void main(String[] args) throws UnknownHostException{ 7 // 獲取本機的InetAdresss實例 8 InetAddress address = InetAddress.getLocalHost(); 9 System.out.println("計算機名:"+address.getHostName()+"\nIP地址:"+address.getHostAddress()); 10 11 // 獲取字節數組形式的IP地址 12 byte[] bytes = address.getAddress(); 13 System.out.println("字節數組形式的IP:"+Arrays.toString(bytes)); 14 System.out.println(address); 15 16 // 也能夠經過機器名來獲取InewAdress 17 InetAddress address2 = InetAddress.getByName("MacBook-Air-2.local"); 18 System.out.println("經過計算機名字建立的InetAddress對象:"+address2); 19 System.out.println("計算機名:"+address2.getHostName()); 20 System.out.println("IP地址:"+address2.getHostAddress()); 21 22 // 也能夠經過IP地址來獲取InewAdress 23 InetAddress address3 = InetAddress.getByName("192.168.1.102"); 24 System.out.println("經過計算機IP地址建立的InetAddress對象:"+address3); 25 System.out.println("計算機名:"+address3.getHostName()); 26 System.out.println("IP地址:"+address3.getHostAddress()); 27 28 29 } 30 }
輸出結果:異步
三、URLsocket
URL(Uniform Resource Locator)統一資源定位符,表示Internet上某一資源的地址。 俗稱就是網址。
URL由兩部分組成:協議名稱+資源名稱。
在Java.net包中,提供了URL類來表示URL。
1 import java.net.MalformedURLException; 2 import java.net.URL; 3 4 public class Test1{ 5 public static void main(String[] args){ 6 7 try { 8 // 建立一個URL實例 9 URL imoocURL = new URL("http://www.imooc.com"); 10 URL url = new URL(imoocURL,"/index.html?username=tom#test"); 11 // ?後面表示參數,#後面表示的是錨點 12 13 // 建立URL對象以後,能夠根據這個對象獲取相關的信息 14 System.out.println("協議:"+url.getProtocol()); 15 System.out.println("主機:"+url.getHost()); 16 // 若是未指定端口號,則使用默認的端口號,此時getPort()方法返回值爲-1 17 System.out.println("端口:"+url.getPort()); 18 System.out.println("文件路徑:"+url.getPath()); 19 System.out.println("文件名:"+url.getFile()); 20 System.out.println("相對路徑:"+url.getRef());// 實際上就是#錨點後面的內容 21 System.out.println("查詢字符串:"+url.getQuery()); 22 23 } catch (MalformedURLException e) { 24 e.printStackTrace(); 25 } 26 27 28 } 29 }
輸出:
下面再經過URL讀取網頁內容:
1 import java.net.MalformedURLException; 2 import java.net.URL; 3 import java.io.InputStream; 4 import java.io.InputStreamReader; 5 import java.io.BufferedReader; 6 import java.io.IOException; 7 8 /* 9 * 使用URL讀取網頁頁面內容 10 */ 11 public class Test1{ 12 public static void main(String[] args){ 13 14 try { 15 // 建立一個URL實例 16 URL url = new URL("http://www.baidu.com"); 17 // 經過URL的openStream方法獲取URL對象所表示的資源的字節輸入流 18 InputStream is = url.openStream(); 19 // 將字節輸入流轉換爲字符輸入流 20 InputStreamReader isr = new InputStreamReader(is,"utf-8");// 若是沒有指明編碼可能會出現中文亂碼 21 // 爲字符輸入流添加緩衝 22 BufferedReader br = new BufferedReader(isr); 23 String data = br.readLine();// 讀取數據 24 while(data != null){ 25 System.out.println(data);// 輸出數據 26 data = br.readLine(); 27 } 28 // 最後按照上面對象倒序關閉 29 br.close(); 30 isr.close(); 31 is.close(); 32 } catch (MalformedURLException e) { 33 e.printStackTrace(); 34 } catch (IOException e) { 35 e.printStackTrace(); 36 } 37 } 38 }
輸入:
四、TCP編程
4-一、Socket簡介
TCP協議是面向鏈接、可靠的、有序的,以字節流的方式發送數據
基於TCP協議實現網絡通訊的類:
>>一、客戶端的Socket類
>>二、服務器端的ServerSocket類
基於Socket的TCP通訊模型
Socket通訊實現步驟:一、建立ServerSocket和Socket。二、打開鏈接到Socket的輸入/輸出流。三、按照協議對Socket進行讀/寫操做。四、關閉輸入輸出流、關閉Socket。
經過在線API文檔:http://tool.oschina.net/apidocs/apidoc?api=jdk-zh 中查詢到的結果:
4-二、編程實現基於TCP的Socket服務器端和客戶端的通訊
服務器端:
一、建立ServerSocket對象,綁定監聽端口。
二、經過accept()方法監聽客戶端請求。
三、連接創建後,經過輸入流讀取客戶端發送的請求信息。
四、經過輸出流向客戶端發送響應信息。
五、關閉相關資源。
1 package com.heyang; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.InputStreamReader; 7 import java.net.ServerSocket; 8 import java.net.Socket; 9 10 /* 11 * 基於TCP協議的Socket通訊,實現用戶登陸 12 * 服務器端 13 */ 14 public class Server { 15 public static void main(String[] args) { 16 try { 17 // 一、建立一個服務器Socket,即ServerSocket,指定綁定的端口,並監聽此端口 18 ServerSocket serverSocket = new ServerSocket(8888); 19 // 二、調用()方法開始監聽,等待客戶端的鏈接 20 System.out.println("***服務器即將啓動,等待客戶端的鏈接***"); 21 Socket socket = serverSocket.accept();// 就會處於阻塞的狀態,等待監聽 22 // 三、獲取輸入流,病讀取客戶端信息 23 InputStream is = socket.getInputStream();// 字節輸入流 24 // 將字節流轉換爲字符流 25 InputStreamReader isr = new InputStreamReader(is); 26 // 爲輸入流添加緩衝 27 BufferedReader br = new BufferedReader(isr); 28 String info = null; 29 while((info = br.readLine())!=null){ 30 System.out.println("我是服務器,讀取客戶端發過來的信息:"+info); 31 } 32 socket.shutdownInput();//關閉輸入流 33 34 // 關閉資源 35 br.close(); 36 isr.close(); 37 is.close(); 38 socket.close(); 39 serverSocket.close(); 40 41 } catch (IOException e) { 42 // TODO Auto-generated catch block 43 e.printStackTrace(); 44 } 45 } 46 }
客戶端:
一、建立Socket對象,指明須要鏈接的服務器的地址和端口號。
二、鏈接創建後,經過輸出流向服務器端發送請求信息。
三、經過輸入流獲取服務器響應的信息。
四、關閉相關資源。
1 package com.heyang; 2 3 import java.io.IOException; 4 import java.io.OutputStream; 5 import java.io.PrintWriter; 6 import java.net.Socket; 7 import java.net.UnknownHostException; 8 9 /* 10 * 客戶端 11 */ 12 public class Client { 13 public static void main(String[] args) { 14 // 一、建立客戶端Socket,指定服務器地址和端口 15 try { 16 Socket socket = new Socket("localhost", 8888); 17 // 二、獲取輸出流,向服務器端發送信息 18 OutputStream os = socket.getOutputStream();// 獲取字節輸出流 19 // 將輸出流包裝爲打印流 20 PrintWriter pw = new PrintWriter(os); 21 pw.write("用戶名:admin 密碼:123"); 22 pw.flush(); 23 socket.shutdownInput();//關閉輸出流 24 25 // 三、關閉資源 26 pw.close(); 27 os.close(); 28 socket.close(); 29 30 } catch (UnknownHostException e) { 31 // TODO Auto-generated catch block 32 e.printStackTrace(); 33 } catch (IOException e) { 34 // TODO Auto-generated catch block 35 e.printStackTrace(); 36 } 37 } 38 }
輸出:
4-三、完善客戶端登錄以後服務器響應客戶端
代碼邏輯深化分析:
在前面簡單的代碼的基礎上,咱們須要完善客戶端登錄以後服務器響應客戶端的邏輯。
事實上,站在客戶端的角度,對外(這裏指的是服務器)發出數據流,也就是須要用輸出流來輸出數據流。
反過來,站在服務器端的角度,就要不斷的監聽外部(這裏指的是外部客戶端)輸入進來的數據流,因此就須要輸入流來接收輸入進來的數據流。
那麼,當服務器端收到客戶端傳輸過來的數據流以後,就應該響應,那麼這時候,站在服務器端的角度,要對外進行響應,就須要用輸出流來輸出響應回饋的信息,這時候就和客戶端一開始的輸出流代 碼一致了。
回到客戶端,因爲須要接收和讀取服務器端的發出的響應,就須要輸入流來接收服務器發過來的回饋信息了,這時候就和服務器端一開始的輸入流代碼一致了。
服務器代碼:
1 package com.heyang; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.InputStreamReader; 7 import java.io.OutputStream; 8 import java.io.PrintWriter; 9 import java.net.ServerSocket; 10 import java.net.Socket; 11 12 /* 13 * 基於TCP協議的Socket通訊,實現用戶登陸 14 * 服務器端 15 */ 16 public class Server { 17 public static void main(String[] args) { 18 try { 19 // 一、建立一個服務器Socket,即ServerSocket,指定綁定的端口,並監聽此端口 20 ServerSocket serverSocket = new ServerSocket(8888); 21 // 二、調用()方法開始監聽,等待客戶端的鏈接 22 System.out.println("***服務器即將啓動,等待客戶端的鏈接***"); 23 Socket socket = serverSocket.accept();// 就會處於阻塞的狀態,等待監聽 24 // 三、獲取輸入流,病讀取客戶端信息 25 InputStream is = socket.getInputStream();// 字節輸入流 26 // 將字節流轉換爲字符流 27 InputStreamReader isr = new InputStreamReader(is); 28 // 爲輸入流添加緩衝 29 BufferedReader br = new BufferedReader(isr); 30 String info = null; 31 while((info = br.readLine())!=null){ 32 System.out.println("我是服務器,讀取客戶端發過來的信息:"+info); 33 } 34 socket.shutdownInput();//關閉輸入流 35 36 // 四、做爲服務器端,就須要響應客戶端的請求,使用輸出流來響應 37 OutputStream os = socket.getOutputStream(); 38 PrintWriter pw = new PrintWriter(os); 39 pw.write("歡迎您!"); 40 pw.flush();//調用flush()方法將緩衝輸出 41 42 43 // 五、關閉資源 44 pw.close(); 45 os.close(); 46 br.close(); 47 isr.close(); 48 is.close(); 49 socket.close(); 50 serverSocket.close(); 51 52 } catch (IOException e) { 53 // TODO Auto-generated catch block 54 e.printStackTrace(); 55 } 56 } 57 }
客戶端代碼:
1 package com.heyang; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.InputStreamReader; 7 import java.io.OutputStream; 8 import java.io.PrintWriter; 9 import java.net.Socket; 10 import java.net.UnknownHostException; 11 12 /* 13 * 客戶端 14 */ 15 public class Client { 16 public static void main(String[] args) { 17 // 一、建立客戶端Socket,指定服務器地址和端口 18 try { 19 Socket socket = new Socket("localhost", 8888); 20 // 二、獲取輸出流,向服務器端發送信息 21 OutputStream os = socket.getOutputStream();// 獲取字節輸出流 22 // 將輸出流包裝爲打印流 23 PrintWriter pw = new PrintWriter(os); 24 pw.write("用戶名:admin 密碼:123"); 25 pw.flush(); 26 socket.shutdownOutput();//關閉輸出流 27 28 // 三、獲取輸入流,並讀取服務器端的響應信息 29 InputStream is = socket.getInputStream(); 30 BufferedReader br = new BufferedReader(new InputStreamReader(is)); 31 String info = null; 32 while((info = br.readLine())!=null){ 33 System.out.println("我是客戶端,服務器跟我說:"+info); 34 } 35 36 // 四、關閉資源 37 br.close(); 38 is.close(); 39 pw.close(); 40 os.close(); 41 socket.close(); 42 43 } catch (UnknownHostException e) { 44 // TODO Auto-generated catch block 45 e.printStackTrace(); 46 } catch (IOException e) { 47 // TODO Auto-generated catch block 48 e.printStackTrace(); 49 } 50 } 51 }
具體運行結果就不展現了。
4-四、使用多線程實現多客戶端的通訊
事實上,以上只實現了單個客戶端和單個服務器端進行socket通訊。那麼問題來了,實際應用程序是由一個服務器持續不斷的運行中,而後由多個客戶端異步經過服務器進行客戶端之間的收發信息,這該如何實現呢?
基本步驟:
一、服務器端建立ServerSocket,循環調用accept()等待客戶端鏈接。
二、客戶端建立一個socket並請求和服務器端鏈接。
三、服務器端接受客戶端請求,建立socket與該客戶端創建專線鏈接。
四、創建鏈接的兩個socket在一個單獨的線程上對話。
五、服務器端繼續等待新的鏈接。
服務器端的代碼:
1 package com.heyang; 2 3 4 import java.io.IOException; 5 import java.net.InetAddress; 6 import java.net.ServerSocket; 7 import java.net.Socket; 8 import com.heyang.ServerThread;; 9 /* 10 * 基於TCP協議的Socket通訊,實現用戶登陸 11 * 服務器端 12 */ 13 public class Server { 14 public static void main(String[] args) { 15 try { 16 // 一、建立一個服務器Socket,即ServerSocket,指定綁定的端口,並監聽此端口 17 ServerSocket serverSocket = new ServerSocket(8888); 18 // 二、調用()方法開始監聽,等待客戶端的鏈接 19 20 // 記錄客戶端的數量 21 int count = 0; 22 System.out.println("***服務器即將啓動,等待客戶端的鏈接***"); 23 24 while(true){ 25 // 調用accept()方法開始監聽,等待客戶端的連接 26 Socket socket = serverSocket.accept(); 27 // 建立一個新的線程 28 ServerThread serverThread = new ServerThread(socket); 29 // 啓動線程· 30 serverThread.start(); 31 32 count++; 33 System.out.println("客戶端鏈接的數量:"+count+"個"); 34 35 // 獲取客戶端的IP地址等信息 36 InetAddress address = socket.getInetAddress(); 37 System.out.println("當前客戶端的IP:"+address.getHostAddress()); 38 39 } 40 41 // 須要死循環持續監聽客戶端的信息發送 42 // serverSocket.close(); 43 44 } catch (IOException e) { 45 // TODO Auto-generated catch block 46 e.printStackTrace(); 47 } 48 } 49 }
服務器線程代碼:
1 package com.heyang; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.InputStreamReader; 7 import java.io.OutputStream; 8 import java.io.PrintWriter; 9 import java.net.Socket; 10 11 /* 12 * 服務器端 線程處理類 13 */ 14 public class ServerThread extends Thread { 15 // 建立和本線程相關的socket 16 Socket socket = null; 17 18 public ServerThread(Socket socket){ 19 this.socket = socket; 20 } 21 22 // 指向線程的操做,響應服務器端的請求 23 public void run(){ 24 25 InputStream is = null; 26 InputStreamReader isr = null; 27 BufferedReader br = null; 28 OutputStream os = null; 29 PrintWriter pw = null; 30 try { 31 // 三、獲取輸入流,病讀取客戶端信息 32 is = socket.getInputStream();// 字節輸入流 33 // 將字節流轉換爲字符流 34 isr = new InputStreamReader(is); 35 // 爲輸入流添加緩衝 36 br = new BufferedReader(isr); 37 String info = null; 38 while ((info = br.readLine()) != null) { 39 System.out.println("我是服務器,讀取客戶端發過來的信息:" + info); 40 } 41 socket.shutdownInput();//關閉輸入流 42 43 // 獲取輸出流 44 os = socket.getOutputStream(); 45 pw = new PrintWriter(os); 46 pw.write("歡迎您!"); 47 pw.flush();//調用flush()方法將緩衝輸出 48 } catch (Exception e) { 49 // TODO: handle exception 50 }finally{ 51 try { 52 // 五、關閉資源 53 if (pw != null) { 54 pw.close(); 55 } 56 if (os != null) { 57 os.close(); 58 } 59 if (br != null) { 60 br.close(); 61 } 62 if (isr != null) { 63 isr.close(); 64 } 65 if (is != null) { 66 is.close(); 67 } 68 if (socket != null) { 69 socket.close(); 70 } 71 } catch (IOException e2) { 72 // TODO: handle exception 73 } 74 } 75 76 77 } 78 79 }
客戶端代碼:
1 package com.heyang; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.InputStreamReader; 7 import java.io.OutputStream; 8 import java.io.PrintWriter; 9 import java.net.Socket; 10 import java.net.UnknownHostException; 11 12 /* 13 * 客戶端 14 */ 15 public class Client { 16 public static void main(String[] args) { 17 // 一、建立客戶端Socket,指定服務器地址和端口 18 try { 19 Socket socket = new Socket("localhost", 8888); 20 // 二、獲取輸出流,向服務器端發送信息 21 OutputStream os = socket.getOutputStream();// 獲取字節輸出流 22 // 將輸出流包裝爲打印流 23 PrintWriter pw = new PrintWriter(os); 24 pw.write("用戶名:admin 密碼:123"); 25 pw.flush(); 26 socket.shutdownOutput();//關閉輸出流 27 28 // 三、獲取輸入流,並讀取服務器端的響應信息 29 InputStream is = socket.getInputStream(); 30 BufferedReader br = new BufferedReader(new InputStreamReader(is)); 31 String info = null; 32 while((info = br.readLine())!=null){ 33 System.out.println("我是客戶端,服務器跟我說:"+info); 34 } 35 36 // 四、關閉資源 37 br.close(); 38 is.close(); 39 pw.close(); 40 os.close(); 41 socket.close(); 42 43 } catch (UnknownHostException e) { 44 // TODO Auto-generated catch block 45 e.printStackTrace(); 46 } catch (IOException e) { 47 // TODO Auto-generated catch block 48 e.printStackTrace(); 49 } 50 } 51 }
運行結果不展現。
五、UDP編程
UDP協議(用戶數據報協議)是無鏈接、不可靠的、無序的。
特色:傳輸速度相對比較快
UDP協議以數據報做爲數據傳輸的載體
進行數據傳輸時,首先須要將要傳輸的數據定義成數據報(Datagram),在數據報中指明數據所要達到的Socket(主機地址和端口號),而後在將數據報發送出去。
相關操做的Java類
DatagramPacket:表示數據報包
DatagramSocket:進行端到端通訊的類
5-一、編程實現基於UDP的Socket通訊之服務器端
5-二、編程實現基於UDP的Socket通訊之客戶端