網絡編程
一、網絡編程的目的:直接或間接地通過網絡協議與其他計算機實現數據交換,進行通訊。
二、網絡編程中兩個主要的問題:
1.如何准確地定位網絡上一台或多台主機;定位主機上的特定的應用
2.找到主機后如何可靠高效的進行數據傳輸。
三、網絡通信的要素:IP 和端口號
網絡通信協議
通信要素一:IP與端口號
一、IP地址:InetAddress
1. IP地址:唯一的標識 Internet 上的計算機(通信實體)
2. 本地回環地址(hostAddress):127.0.0.1 主機名(hostName):localhost
3. IP 分類:IPV4 和 IPV6 ;(公網地址)萬維網與(私有地址)局域網
4. 域名:www.mi.com等
5.本地回路地址:127.0.0.1 對應着: localhost
6.如何實例化InetAddress:兩個方法:getByName(String host)、getLocalHost()
兩個常用方法:getHostName()、getHostAddress()

public class InetAddressTest { public static void main(String[] args) { try { InetAddress inet1 = InetAddress.getByName("192.168.0.1"); System.out.println(inet1); InetAddress inet2 = InetAddress.getByName("www.baidu.com"); System.out.println(inet2); InetAddress inet3 = InetAddress.getByName("127.0.0.1"); System.out.println(inet3); //獲取本地ip InetAddress inet4 = InetAddress.getLocalHost(); System.out.println(inet4); //getHostName() System.out.println(inet2.getHostName()); //getHostAddress() System.out.println(inet2.getHostAddress()); } catch (UnknownHostException e) { e.printStackTrace(); } } }
二、端口號:標識正在計算機上運行的程序。
1. 不同的進程有不同的端口號。
2. 端口分類:公認端口(0~1023) 、注冊端口(1024~49151) 、動態/私有端口:49152~65535。
3. 范圍:被規定為一個16位的整數 0~65535
4. 端口號與IP地址的組合得出一個網絡套接字:Socket。
三、InetAddress類
1. Internet上的主機有兩種方式表示地址:域名(hostName)、IP 地址(hostAddress)
2. InetAddress類主要表示IP地址,兩個子類:Inet4Address、Inet6Address。
//InetAddress類沒有提供公共的構造器,而是提供了如下幾個靜態方法來獲取 //InetAddress實例 public static InetAddress getLocalHost() public static InetAddress getByName(String host) //InetAddress提供了如下幾個常用的方法 public String getHostAddress():返回 IP 地址字符串(以文本表現形式)。 public String getHostName():獲取此 IP 地址的主機名 public boolean isReachable(int timeout):測試是否可以達到該地址
通信要素2:網絡通信協議
計算機網絡中實現通信必須有一些約定,即通信協議,對速率、傳輸代碼、代碼結構、傳輸控制步驟、出錯控制等制定標准。
一、傳輸層協議中有兩個非常重要的協議:傳輸控制協議TCP(Transmission Control Protocol)
TCP和UDP
- 使用TCP協議前,須先建立TCP連接,形成傳輸數據通道
- 傳輸前,采用“三次握手”方式,點對點通信,是可靠的
- TCP協議進行通信的兩個應用進程:客戶端、服務端。
- 在連接中可進行大數據量的傳輸
- 傳輸完畢,需釋放已建立的連接,效率低
TCP三次握手:
TCP四次揮手:1.傳輸斷開連接信息
2.發送斷開信息
3.斷開連接
4.驗證是否斷開
- 將數據、源、目的封裝成數據包,不需要建立連接
- 每個數據報的大小限制在64K內
- 發送不管對方是否准備好,接收方收到也不確認,故是不可靠的
- 可以廣播發送
- 發送數據結束時無需釋放資源,開銷小,速度快
Socket:網絡上具有唯一標識的IP地址和端口號組合在一起才能構成唯一能識別的標識符套接字。
TCP網絡編程
- 創建 Socket:根據指定服務端的 IP 地址或端口號構造 Socket 類對象。若服務器端響應,則建立客戶端到服務器的通信線路。若連接失敗,會出現異常。
- 打開連接到 Socket 的輸入/出流: 使用 getInputStream()方法獲得輸入流,使用getOutputStream()方法獲得輸出流,進行數據傳輸
- 按照一定的協議對 Socket 進行讀/寫操作:通過輸入流讀取服務器放入線路的信息(但不能讀取自己放入線路的信息),通過輸出流將信息寫入線程。
- 關閉 Socket:斷開客戶端到服務器的連接,釋放線路
- 調用 ServerSocket(int port) :創建一個服務器端套接字,並綁定到指定端口上。用於監聽客戶端的請求。
- 調用 accept():監聽連接請求,如果客戶端請求連接,則接受連接,返回通信套接字對象。
- 調用 該Socket類對象的 getOutputStream() 和 getInputStream ():獲取輸出流和輸入流,開始網絡數據的發送和接收。
- 關閉ServerSocket和Socket對象:客戶端訪問結束,關閉通信套接字。

/** * 實現TCP的網絡編程 * 例子1:客戶端發送信息給服務端,服務端將數據顯示在控制台上 * */ public class TCPTest1 { //客戶端 @Test public void client() { Socket socket = null; OutputStream os = null; try { //1.創建Socket對象,指明服務器端的ip和端口號 InetAddress inet = InetAddress.getByName("192.168.14.100"); socket = new Socket(inet,8899); //2.獲取一個輸出流,用於輸出數據 os = socket.getOutputStream(); //3.寫出數據的操作 os.write("你好,我是客戶端mm".getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { //4.資源的關閉 if(os != null){ try { os.close(); } catch (IOException e) { e.printStackTrace(); } } if(socket != null){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } //服務端 @Test public void server() { ServerSocket ss = null; Socket socket = null; InputStream is = null; ByteArrayOutputStream baos = null; try { //1.創建服務器端的ServerSocket,指明自己的端口號 ss = new ServerSocket(8899); //2.調用accept()表示接收來自於客戶端的socket socket = ss.accept(); //3.獲取輸入流 is = socket.getInputStream(); //不建議這樣寫,可能會有亂碼 // byte[] buffer = new byte[1024]; // int len; // while((len = is.read(buffer)) != -1){ // String str = new String(buffer,0,len); // System.out.print(str); // } //4.讀取輸入流中的數據 baos = new ByteArrayOutputStream(); byte[] buffer = new byte[5]; int len; while((len = is.read(buffer)) != -1){ baos.write(buffer,0,len); } System.out.println(baos.toString()); System.out.println("收到了來自於:" + socket.getInetAddress().getHostAddress() + "的數據"); } catch (IOException e) { e.printStackTrace(); } finally { if(baos != null){ //5.關閉資源 try { baos.close(); } catch (IOException e) { e.printStackTrace(); } } if(is != null){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if(socket != null){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if(ss != null){ try { ss.close(); } catch (IOException e) { e.printStackTrace(); } } } } }

/** * * 實現TCP的網絡編程 * 例題2:客戶端發送文件給服務端,服務端將文件保存在本地。 * */ public class TCPTest2 { /* 這里涉及到的異常,應該使用try-catch-finally處理 */ @Test public void client() throws IOException { //1. Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9090); //2. OutputStream os = socket.getOutputStream(); //3. FileInputStream fis = new FileInputStream(new File("beauty.jpg")); //4. byte[] buffer = new byte[1024]; int len; while((len = fis.read(buffer)) != -1){ os.write(buffer,0,len); } //5. fis.close(); os.close(); socket.close(); } /* 這里涉及到的異常,應該使用try-catch-finally處理 */ @Test public void server() throws IOException { //1. ServerSocket ss = new ServerSocket(9090); //2. Socket socket = ss.accept(); //3. InputStream is = socket.getInputStream(); //4. FileOutputStream fos = new FileOutputStream(new File("beauty1.jpg")); //5. byte[] buffer = new byte[1024]; int len; while((len = is.read(buffer)) != -1){ fos.write(buffer,0,len); } //6. fos.close(); is.close(); socket.close(); ss.close(); } }
- 類 DatagramSocket 和 DatagramPacket 實現了基於 UDP 協議網絡程序。
- UDP數據報通過數據報套接字 DatagramSocket 發送和接收,系統不保證UDP數據報一定能夠安全送到目的地,也不能確定什么時候可以抵達。
- DatagramPacket 對象封裝了UDP數據報,在數據報中包含了發送端的IP地址和端口號以及接收端的IP地址和端口號。
- UDP協議中每個數據報都給出了完整的地址信息,因此無須建立發送方和接收方的連接。如同發快遞包裹一樣。

/** * UDPd協議的網絡編程 * @author shkstart */ public class UDPTest { //發送端 @Test public void sender() throws IOException { DatagramSocket socket = new DatagramSocket(); String str = "我是UDP方式發送的導彈"; byte[] data = str.getBytes(); InetAddress inet = InetAddress.getLocalHost(); DatagramPacket packet = new DatagramPacket(data,0,data.length,inet,9090); socket.send(packet); socket.close(); } //接收端 @Test public void receiver() throws IOException { DatagramSocket socket = new DatagramSocket(9090); byte[] buffer = new byte[100]; DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length); socket.receive(packet); System.out.println(new String(packet.getData(),0,packet.getLength())); socket.close(); } }

/** * URL網絡編程 * 1.URL:統一資源定位符,對應着互聯網的某一資源地址 * 2.格式: * http://localhost:8080/examples/beauty.jpg?username=Tom * 協議 主機名 端口號 資源地址 參數列表 */ public class URLTest { public static void main(String[] args) { try { URL url = new URL("http://localhost:8080/examples/beauty.jpg?username=Tom"); // public String getProtocol( ) 獲取該URL的協議名 System.out.println(url.getProtocol()); // public String getHost( ) 獲取該URL的主機名 System.out.println(url.getHost()); // public String getPort( ) 獲取該URL的端口號 System.out.println(url.getPort()); // public String getPath( ) 獲取該URL的文件路徑 System.out.println(url.getPath()); // public String getFile( ) 獲取該URL的文件名 System.out.println(url.getFile()); // public String getQuery( ) 獲取該URL的查詢名 System.out.println(url.getQuery()); } catch (MalformedURLException e) { e.printStackTrace(); } } }
.