經過通訊線路(有線或無線)能夠把不一樣地理位置且相互獨立的計算機連同其外部設備鏈接起來,組成計算機網絡。在操做系統、網絡管理軟件及網絡通訊協議的管理和協調下,能夠實現計算機之間的資源共享和信息的傳遞。java
網絡編程是指用來實現網絡互聯的不一樣計算機上運行的程序間能夠進行數據交換。對咱們來講即如何用編程語言 java 實現計算機網絡中不一樣計算機之間的通訊。編程
網絡中計算機的惟一標識;服務器
32bit(4 字節),通常用「點分十進制」表示,如 192.168.1.158; IP 地址=網絡地址+主機地址 可分類:網絡
A 類:第 1 個 8 位表示網絡地址。剩下的 3 個 8 位表示主機地址 (主要留給ZF或者大型企業)多線程
B 類:前 2 個 8 位表示網絡地址。剩下的 2 個 8 位表示主機地址 (主要分配給中等規模的公司)socket
C 類:前 3 個 8 位表示網絡地址。剩下的 1 個 8 位表示主機地址 (分配給小公司或者我的)tcp
D 類地址用於在 IP 網絡中的組播編程語言
E 類地址保留做研究之用。函數
Java 編程中可以使用 InetAddress 類來操縱 IP 地址this
public static void main(String[] args) throws UnknownHostException {
InetAddress localHost = InetAddress.getLocalHost(); System.out.println(localHost.getHostAddress()); System.out.println(localHost.getHostName());
}
用於標識進程的邏輯地址,不一樣進程的標識;
有效端口:0-65535,其中 0-1024 系統使用或保留端口。
通信的規則
常見協議: UDP(用戶數據報協議)、TCP(傳輸控制協議)
計算機網絡之間以何種規則進行通訊,就是網絡模型所研究的問題。 網絡模型通常是指 OSI 七層參考模型和 TCP/IP 五層參考模型。
每一層實現各自的功能和協議,而且都爲上一層提供業務功能。爲了提供這種業務功能,下一層將上一層中的數據併入到本層的數據域中,而後經過加入報頭或報尾來實現該層業務功能,該過程叫作數據封裝。用戶的數據要通過一次次包裝,最後轉化成能夠在網絡上傳輸的信號,發送到網絡上。當到達目標計算機後,再執行相反的數據拆包過程。
物理層:
主要定義物理設備標準,如網線的接口類型、光纖的接口類型、各類傳輸介質的傳輸速率等。
主要做用是將數據最終編碼爲用 0、1 標識的比特流,經過物理介質傳輸。 這一層的數據叫作比特。
數據鏈路層:
主要將接收到的數據進行 MAC 地址(網卡地址)的封裝與解封裝。 常把這一層的數據叫作幀。這一層常工做的設備是交換機。
網絡層:
主要將接收到的數據進行 IP 地址的封裝與解封裝。
常把這一層的數據叫作數據包。這一層設備是路由器。
傳輸層:
定義了一些數據傳輸的協議和端口號。
主要將接收的數據進行分段和傳輸,到達目的地址後在進行重組。 常把這一層的數據叫作段。
會話層:
經過傳輸層創建數據傳輸的通路。
主要在系統之間發起會話或者接收會話請求。
表示層:
主要進行對接收數據的解釋、加密與解密、壓縮與解壓縮。
確保一個系統的應用層發送的數據能被另外一個系統的應用層識別。
應用層:
主要是爲一些終端應用程序提供服務。直接面對着用戶的
Socket,又稱爲套接字,用於描述 IP 地址和端口。應用程序一般經過 socket向網絡發出請求或者應答網絡請求。Socket 就是爲網絡編程提供的一種機制:
通訊兩端都有 socket;
網絡通訊其實就是 socket 之間的通訊;
數據在兩個 socket 之間經過 IO 傳輸。
網絡編程也稱做爲 Socket 編程,套接字編程。
Socket 通訊是 Client/Server 模型。
核心類:DatagramSocket
發送端:
// 建立發送端 Socket 服務對象
DatagramSocket dSocket = new DatagramSocket();
// 建立數據,打包數據
String message = "hello ,are u UDP ?";
byte[] bys = message.getBytes();
int length = bys.length;
InetAddress address = InetAddress.getByName("localhost");
int port = 12621;
DatagramPacket dPacket = new DatagramPacket(bys, length, address, port);
// 發送數據
dSocket.send(dPacket);
// 資源釋放
dSocket.close();
接收端:
//建立接收端Socket 服務對象
DatagramSocket dSocket = new DatagramSocket(12621);
//建立數據包(接收容器)
byte[] bys = new byte[1024];
DatagramPacket dPacket = new DatagramPacket(bys, bys.length);
//調用接收方法
dSocket.receive(dPacket);
//數據包解析
InetAddress address = dPacket.getAddress();
String hostAddress = address.getHostAddress();
byte[] data = dPacket.getData();
String message = new String(data);
System.out.println(hostAddress+"*********:"+message);
//資源釋放
dSocket.close();
核心 API:ServerSocket
流程:
建立 ServerSocket 服務,而後綁定在服務器的 IP 地址和端口
監聽鏈接請求
接受請求,創建了 TCP 鏈接
獲取輸入流讀取數據,並顯示
釋放資源
//創建服務端socket 服務,而且監聽一個端口
ServerSocket ss = new ServerSocket(13131);
//監聽鏈接
Socket s = ss.accept();
//獲取輸入流,讀取數據
InputStream inputStream = s.getInputStream();
byte[] bys = new byte[1024];
int len = inputStream.read(bys);
System.out.println(new String(bys, 0, len));
//關閉客戶端
s.close();
//關閉服務端,通常服務端不關閉 ss.close();
客戶端
核心 API:Socket
流程:
建立客戶端 socket 對象
向服務端請求創建 tcp 鏈接
從 tcp 鏈接中獲取輸出流,寫數據 釋放資源
//建立客戶端的socket 服務,指定目的主機和端口
Socket s = new Socket("127.0.0.1", 13131);
//經過socket 獲取輸出流,寫數據
OutputStream outputStream = s.getOutputStream(); outputStream.write("hello ,this is tcp?".getBytes());
//釋放資源
s.close();
網絡通訊的本質是網絡間的數據 IO。只要有 IO,就會有阻塞或非阻塞的問題,不管這個 IO 是網絡的,仍是硬盤的。緣由在於程序是運行在系統之上的,任何形式的IO 操做發起都須要系統內核的支持。
BIO 即 blocking IO,是一種阻塞式的 IO。
jdk1.4 版本以前 Socket 即 BIO 模式。
BIO 的問題在於 accept()、read()的操做點都是被阻塞的。
服務器線程發起一個 accept 動做,詢問操做系統是否有新的 socket 信息從端口 X 發送過來。注意,是詢問操做系統。若是操做系統沒有發現有 socket 從指定的端口X 來,那麼操做系統就會等待。這樣 serverSocket.accept()方法就會一直等待。這就是爲何 accept()方法爲何會阻塞。
若是想讓 BIO 同時處理多個客戶端請求,就必須使用多線程,即每次 accept阻塞等待來自客戶端請求,一旦收到鏈接請求就創建通訊,同時開啓一個新的線程來處理這個套接字的數據讀寫請求,而後馬上又繼續 accept 等待其餘客戶端鏈接請求,即爲每個客戶端鏈接請求都建立一個線程來單獨處理。
NIO 即 non-blocking IO,是一種非阻塞式的 IO。jdk1.4 以後提供。
NIO 三大核心部分:Channel(通道),Buffer(緩衝區), Selector(選擇器)。 Buffer:容器對象,包含一些要寫入或者讀出的數據。在 NIO 庫,全部數據都是用緩衝區處理的。在讀取數據時,它是直接讀到緩衝區中的;在寫入數據時,也是寫入到緩衝區中。任什麼時候候訪問 NIO 中的數據,都是經過緩衝區進行操做。
Channel:通道對象,對數據的讀取和寫入要經過 Channel,它就像水管同樣。通道不一樣於流的地方就是通道是雙向的,能夠用於讀、寫和同時讀寫操做。 Channel不會直接處理字節數據,而是經過 Buffer 對象來處理數據。
Selector:多路複用器,選擇器。提供選擇已經就緒的任務的能力。Selector會不斷輪詢註冊在其上的 Channel,若是某個 Channel 上面發生讀或者寫事件,這個Channel 就處於就緒狀態,會被 Selector 輪詢出來,進行後續的 I/O 操做。這樣服務器只須要一兩個線程就能夠進行多客戶端通訊。
阻塞 IO 和非阻塞 IO 這兩個概念是程序級別的。主要描述的是程序請求操做系統IO 操做後,若是 IO 資源沒有準備好,那麼程序該如何處理的問題:前者等待;後者繼續執行(而且使用線程一直輪詢,直到有 IO 資源準備好了)。
同步 IO 和非同步 IO,這兩個概念是操做系統級別的。主要描述的是操做系統在收到程序請求 IO 操做後,若是 IO 資源沒有準備好,該如何響應程序的問題:前者不響應,直到 IO 資源準備好之後;後者返回一個標記(好讓程序和本身知道之後的數據往哪裏通知),當 IO 資源準備好之後,再用事件機制返回給程序。
RPC(Remote Procedure Call Protocol)遠程過程調用協議。
通俗的描述是:客戶端在不知道調用細節的狀況下,調用存在於遠程計算機上的某個過程或函數,就像調用本地應用程序中的同樣。
正式的描述是:一種經過網絡從遠程計算機程序上請求服務,而不須要了解底層網絡技術的協議。
RPC 是協議:協議意味着規範。目前典型的 RPC 實現包括:Dubbo、Thrift、 Hetty等。但這些實現每每都會附加其餘重要功能,例如 Dubbo 還包括了服務管理、訪問權限管理等功能。
網絡協議和網絡 IO 模型對其透明:既然 RPC 的客戶端認爲本身是在調用本地對象。那麼傳輸層使用的是 TCP/UDP 仍是 HTTP 協議,又或者是一些其餘的網絡協議它就不須要關心了。既然網絡協議對其透明,那麼調用過程當中,使用的是哪種網絡IO 模型調用者也不須要關心。
信息格式對其透明:遠程調用過程當中,須要傳遞一些參數,而且會返回一個調用結果。至於這些參數會以某種信息格式傳遞給網絡上的另一臺計算機,這個信息格式是怎樣構成的,調用方是不須要關心的。
跨語言能力:對於調用方來講,不知道也無需知道遠程的程序使用的是什麼語言運行的,不管服務器方使用的是什麼語言,本次調用都應該成功,而且返回值也應該按照調用方程序語言所能理解的形式進行描述。
實現 RPC 的程序包括 5 個部分:User、User-stub、RPCRuntime、Server-stub、Server。
user 就是發起 RPC 調用的 client ,當 user 想發起一個遠程調用時,它實際是經過本地調用 user-stub。 user-stub 負責將調用的接口、方法和參數經過約定的協議規範進行編碼並經過本地的 RPCRuntime 實例傳輸到遠端的實例。遠端RPCRuntim 實例收到請求後交給 server-stub 進行解碼後發起本地端調用,調用結果再返回給 user 端。
stub:爲屏蔽客戶調用遠程主機上的對象,必須提供某種方式來模擬本地對象,這種本地對象稱爲存根(stub),存根負責接收本地方法調用,並將它們委派給各自的具體實現對象。