Java--Socket通信
下面內容是Java開發內容的高級知識點,需要對Java中的面向對象、IO、多線程、以及網絡相關知識有一定的基礎。(知識永遠都有深度,本章節長期更新內容)
?
1、網絡基礎知識
?
網絡通信的條件:1、兩個通信的端都要有各自的IP地址作為唯一標識,簡單的來說IP地址用來區分不同機器(計算機)。2、語言要相通。3、如何辨別不同程序的通信需要端口號來區別,簡單的來說端口號就是用來標識不同的應用程序。
TCP/IP是目前世界上使用最廣泛的協議,是以TCP和IP為基礎的不同層次上多個協議的集合,也稱TCP/IP協議族 或 TCP/IP 協議棧。
TCP:Transmission Control Protocol 傳輸控制協議
IP:Internet Protocol 互聯網協議
TCP/IP模型
?
>>IP和端口<<
1、用于區分不同應用程序。
2、端口號范圍為0~65535,其中0~1023為系統所保留。如果自定義端口號,所以建議用1024之后的端口號。
3、IP地址和端口號組成了所謂的Socket,Socket是網絡上運行程序之間雙向通信鏈路的終結點,是TCP和UDP的基礎。
常用的端口號需要記一下:http:80??? ftp:21??? telnet:23
?
——————————Java中的網絡支持—————————
針對網絡通信的不同層次,Java提供的網絡功能有四大類:
>>1、InetAddress:用于標識網絡上的硬件資源
>>2、URL:統一資源定位符 通過URL可以直接讀取或寫入網絡上的數據
>>3、Socket:使用TCP協議實現網絡通信的Socket相關的類。
>>4、Datagram:使用UDP協議,將數據保存在數據報中,通過網絡進行通信。
?
2、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 }輸出結果:
?
?
3、URL
?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 }輸入:
?
4、TCP編程
4-1、Socket簡介
TCP協議是面向連接、可靠的、有序的,以字節流的方式發送數據
基于TCP協議實現網絡通信的類:
>>1、客戶端的Socket類
>>2、服務器端的ServerSocket類
基于Socket的TCP通信模型
?
?Socket通信實現步驟:1、創建ServerSocket和Socket。2、打開連接到Socket的輸入/輸出流。3、按照協議對Socket進行讀/寫操作。4、關閉輸入輸出流、關閉Socket。
通過在線API文檔:http://tool.oschina.net/apidocs/apidoc?api=jdk-zh?中查詢到的結果:
4-2、編程實現基于TCP的Socket服務器端和客戶端的通信
服務器端:
?? ?1、創建ServerSocket對象,綁定監聽端口。
?? ?2、通過accept()方法監聽客戶端請求。
?? ?3、鏈接建立后,通過輸入流讀取客戶端發送的請求信息。
?? ?4、通過輸出流向客戶端發送響應信息。
?? ?5、關閉相關資源。
客戶端:
?? ?1、創建Socket對象,指明需要連接的服務器的地址和端口號。
?? ?2、連接建立后,通過輸出流向服務器端發送請求信息。
?? ?3、通過輸入流獲取服務器響應的信息。
?? ?4、關閉相關資源。
輸出:
?
?4-3、完善客戶端登陸之后服務器響應客戶端
代碼邏輯深化分析:
在前面簡單的代碼的基礎上,我們需要完善客戶端登陸之后服務器響應客戶端的邏輯。
事實上,站在客戶端的角度,對外(這里指的是服務器)發出數據流,也就是需要用輸出流來輸出數據流。
反過來,站在服務器端的角度,就要不斷的監聽外部(這里指的是外部客戶端)輸入進來的數據流,所以就需要輸入流來接收輸入進來的數據流。
那么,當服務器端收到客戶端傳輸過來的數據流之后,就應該響應,那么這時候,站在服務器端的角度,要對外進行響應,就需要用輸出流來輸出響應回饋的信息,這時候就和客戶端一開始的輸出流代 碼一致了。
回到客戶端,由于需要接收和讀取服務器端的發出的響應,就需要輸入流來接收服務器發過來的回饋信息了,這時候就和服務器端一開始的輸入流代碼一致了。
?
服務器代碼:
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 // 1、創建一個服務器Socket,即ServerSocket,指定綁定的端口,并監聽此端口 20 ServerSocket serverSocket = new ServerSocket(8888); 21 // 2、調用()方法開始監聽,等待客戶端的連接 22 System.out.println("***服務器即將啟動,等待客戶端的連接***"); 23 Socket socket = serverSocket.accept();// 就會處于阻塞的狀態,等待監聽 24 // 3、獲取輸入流,病讀取客戶端信息 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 // 4、作為服務器端,就需要響應客戶端的請求,使用輸出流來響應 37 OutputStream os = socket.getOutputStream(); 38 PrintWriter pw = new PrintWriter(os); 39 pw.write("歡迎您!"); 40 pw.flush();//調用flush()方法將緩沖輸出 41 42 43 // 5、關閉資源 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 // 1、創建客戶端Socket,指定服務器地址和端口 18 try { 19 Socket socket = new Socket("localhost", 8888); 20 // 2、獲取輸出流,向服務器端發送信息 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 // 3、獲取輸入流,并讀取服務器端的響應信息 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 // 4、關閉資源 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-4、使用多線程實現多客戶端的通信
?事實上,以上只實現了單個客戶端和單個服務器端進行socket通信。那么問題來了,實際應用程序是由一個服務器持續不斷的運行中,然后由多個客戶端異步通過服務器進行客戶端之間的收發信息,這該如何實現呢?
?基本步驟:
1、服務器端創建ServerSocket,循環調用accept()等待客戶端連接。
2、客戶端創建一個socket并請求和服務器端連接。
3、服務器端接受客戶端請求,創建socket與該客戶端建立專線連接。
4、建立連接的兩個socket在一個單獨的線程上對話。
5、服務器端繼續等待新的連接。
服務器端的代碼:
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 // 1、創建一個服務器Socket,即ServerSocket,指定綁定的端口,并監聽此端口 17 ServerSocket serverSocket = new ServerSocket(8888); 18 // 2、調用()方法開始監聽,等待客戶端的連接 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 // 3、獲取輸入流,病讀取客戶端信息 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 // 5、關閉資源 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 // 1、創建客戶端Socket,指定服務器地址和端口 18 try { 19 Socket socket = new Socket("localhost", 8888); 20 // 2、獲取輸出流,向服務器端發送信息 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 // 3、獲取輸入流,并讀取服務器端的響應信息 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 // 4、關閉資源 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 }運行結果不展示。
5、UDP編程
UDP協議(用戶數據報協議)是無連接、不可靠的、無序的。
特點:傳輸速度相對比較快
UDP協議以數據報作為數據傳輸的載體
進行數據傳輸時,首先需要將要傳輸的數據定義成數據報(Datagram),在數據報中指明數據所要達到的Socket(主機地址和端口號),然后在將數據報發送出去。
?
相關操作的Java類
DatagramPacket:表示數據報包
DatagramSocket:進行端到端通信的類
?
?
?
5-1、編程實現基于UDP的Socket通信之服務器端
?
5-2、編程實現基于UDP的Socket通信之客戶端
?
轉載于:https://www.cnblogs.com/iOS-mt/p/8676918.html
總結
以上是生活随笔為你收集整理的Java--Socket通信的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到那个人说明什么
- 下一篇: 梦到桃花林盛开了好不好