網絡編程java
網絡通訊協議分層思想編程
爲何要分層呢?由於整個網絡協議很是複雜,要涉及到方方面面的知識,並且還有對底層硬件的操做,利用分層的思想,咱們能夠將複雜的通訊協議分割成一層層的形式,上一層能夠調用下一層,而與再下一層不發生關係,各層之間互不影響,便於系統的開發。咱們把用戶程序做爲最高層,把物理通訊線路做爲最底層,高層到底層一步步封裝,咱們不須要直接操做底層,而是操做最簡單的最高層,這就是分層的意義。服務器
參考模型網絡
物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層socket
應用層、傳輸層(TCP/UDP層)、網絡層(IP層)、數據鏈路層、物理層.net
咱們今天要講的主要是傳輸層。3d
IP協議code
IP層:給咱們作的最大貢獻就是提供了獨一無二的IP地址。server
IP TCP UDP 網關 內網 子網掩碼對象
UDP是User Datagram Protocol的簡稱,是一種無鏈接的協議。UDP是從一臺計算機向另外一臺計算機發送稱爲數據報的獨立數據包的協議,該協議並不保證數據報是否能正確地到達目的地,它是一個非面向鏈接的協議。每一個數據報都是一個獨立的信息,包括完整的源地址或目的地址,它在網絡上以任何可能的路徑傳往目的地,所以可否到達目的地,到達時間以及內容的正確性都是不能保證的。
端口:用於區分不一樣的網絡應用程序 ,佔兩個字節,因此共有 65535 個端口號。不過系統會隨時徵用 1024 如下端口。
端口又分TCP和UDP端口,各有 65535 個端口。
TCP Socket 通訊模型
示例1:最簡單的Socket模型:Client寫數據務器讀數據
// Server import java.net.*; import java.io.*; public class Server { public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(6666); // 已經開始監聽6666端口了 while(true) { Socket s = ss.accept(); // ss創建一個插座Socket,接受和客戶端s的鏈接(阻塞式鏈接),鏈接成功,至關於服務器和客戶端之間鏈接了兩根管道。讀的管道(InputStream)和寫的管道(OutputStream)。 System.out.println("A Client has Connected!"); DataInputStream dis = new DataInputStream(s.getInputStream()); System.out.println(dis.readUTF());// 因此先獲取管道,要說就獲取寫的管道,要聽就獲取讀的管道。 dis.close(); s.close(); } } } // Client import java.net.*; import java.io.*; public class Client { public static void main(String[] args) throws Exception { Socket s = new Socket("127.0.0.1", 6666);// 申請和ss創建鏈接 DataOutputStream dos = new DataOutputStream(s.getOutputStream()); dos.writeUTF("Hello TCP."); // 鏈接好以後開始說話,經過管道流的方式來講話,因此先獲取管道,要說就獲取寫的管道,要聽就獲取讀的管道。 dos.flush(); dos.close(); s.close(); } }
Client 端的 IP 地址不能隨意指定,不知爲什麼。
示例2:服務器向客戶端發送數據,客戶端接收數據
// Server import java.net.*; import java.io.*; public class Server { public static void main(String[] args) { try { ServerSocket ss = new ServerSocket(6666); while(true) { Socket s = ss.accept(); System.out.println("A Client has Connected!"); DataOutputStream dos = new DataOutputStream(s.getOutputStream()); dos.writeUTF("Hi [#IP:" + s.getInetAddress() + " #Port:" + s.getPort() + "], I'm Server."); dos.close(); s.close(); } } catch (IOException e) { System.out.println("Server Error!!!"); e.printStackTrace(); } } } // Client import java.net.*; import java.io.*; public class Client { public static void main(String[] args) { try { Socket s = new Socket("127.0.0.1", 6666); DataInputStream dis = new DataInputStream(s.getInputStream()); System.out.println(dis.readUTF()); dis.close(); s.close(); } catch(IOException e) { System.out.println("Client Error!!!"); e.printStackTrace(); } } } //I:\Java\Demo>java Client //Hi [#IP:/127.0.0.1 #Port:15944], I'm Server. //I:\Java\Demo>java Client //Hi [#IP:/127.0.0.1 #Port:15953], I'm Server. //I:\Java\Demo>java Client //Hi [#IP:/127.0.0.1 #Port:15954], I'm Server. //I:\Java\Demo>java Client //Hi [#IP:/127.0.0.1 #Port:15955], I'm Server.
示例3:服務器和客戶端同時讀寫數據(固然一個先讀一個先寫嘍,若是兩個都讀或都寫的話就卡死啦)
// Server // 服務器先接收客戶端的數據,而後再發送數據給客戶端 import java.net.*; import java.io.*; public class Server { public static void main(String[] args) { try { ServerSocket ss = new ServerSocket(6666); Socket s = ss.accept(); System.out.println("A Client has Connected!"); DataInputStream dis = new DataInputStream(s.getInputStream()); DataOutputStream dos = new DataOutputStream(s.getOutputStream()); String str = null; if((str=dis.readUTF()) != null) { System.out.println("I'm reseaving message..."); Thread.sleep(3000); dos.writeUTF("Hi [#IP:" + s.getInetAddress() + " #Port:" + s.getPort() + "], I hava reseaved: " + str); } dis.close(); dos.close(); s.close(); } catch (IOException e) { System.out.println("Server Error!!!"); e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } // Client // 客戶端先發送數據給服務器,再接收服務器的回覆。 import java.net.*; import java.io.*; public class Client { public static void main(String[] args) { try { Socket s = new Socket("localhost", 6666); DataInputStream dis = new DataInputStream(s.getInputStream()); DataOutputStream dos = new DataOutputStream(s.getOutputStream()); System.out.println("Hi Server, I'm sending message to you..."); Thread.sleep(2000); dos.writeUTF("Hello HYJ."); System.out.println(dis.readUTF()); dis.close(); s.close(); } catch(UnknownHostException e) { e.printStackTrace(); } catch(IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }
注意:這裏面使用的是 Socket s = new Socket("localhost", 6666);
最後要 catch(UnknownHostException e),UnknownHostException 小於 IOException 因此要放前面。
UDP 通訊模型
示例:
// UDPServer 接收並打印來自客戶端的數據 import java.net.*; import java.io.*; public class UDPServer { public static void main(String[] args) { try { byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, buf.length); DatagramSocket ds = new DatagramSocket(8888); while(true) { ds.receive(dp); //ByteArrayInputStream bais = new ByteArrayInputStream(buf); //DataInputStream dis = new DataInputStream(bais); //System.out.println("UDPClient: " + dis.readUTF()); System.out.println("UDPClient: " + new String(buf, 0, dp.getLength())); } } catch (IOException e) { System.out.println("UDPServer Error!!!"); e.printStackTrace(); } } } // UDPClient 發送數據給服務器 import java.net.*; import java.io.*; public class UDPClient { public static void main(String[] args) { try { //ByteArrayOutputStream baos = new ByteArrayOutputStream(); //DataOutputStream dos = new DataOutputStream(baos); //dos.writeUTF("Hello HYJ!"); //dos.flush(); //byte[] buf = baos.toByteArray(); byte[] buf = (new String("Hello HYJ!")).getBytes(); System.out.println("buf.length = " + buf.length); DatagramPacket dp = new DatagramPacket(buf, buf.length, new InetSocketAddress("127.0.0.1", 8888)); DatagramSocket ds = new DatagramSocket(7777); ds.send(dp); ds.close(); } catch(IOException e) { e.printStackTrace(); } } }