本文闡述了socket編程、IO網路模型,以及各種IO模型的適用場景,
RPC架構設計
文章更新歷史
2022/03/01 初稿,
2022/05/04 修改相關描述,
socket
socket網路編程
socket概述
socket套接字是兩臺主機之間邏輯連接的端點,
TCP/IP協議是傳輸層協議,主要解決資料在網路中的傳輸
socket是網路通信之間的抽象介面,它包含網路通信的五種基礎資訊:連接使用的協議、本地主機的ip地址、本地行程協議埠、遠程主機ip地址、遠程行程的協議埠,
socket整體流程
socket編程主要包括客戶端和服務端兩個方面,
首先在服務端創建一個服務端套接字(ServerSocket),并把它附加到一個埠上,服務端從這個埠監聽鏈接,
埠范圍是 0-65536 ,注意 0-1024 是特權服務保留的埠,可選擇任意一個不被其他行程使用的埠,
客戶端請求與服務端連接時,根據服務端的域名或者ip地址,加上埠號,打開一個套接字,當服務器接受連接后,服務器和客戶端之間的操作可以像輸入輸出流一樣操作,

代碼實作
-
服務端代碼
/** * 服務端 * * @name: ServerDemo * @author: terwer * @date: 2022-04-17 14:20 **/ public class ServerDemo { public static void main(String[] args) throws IOException { // 1.創建一個執行緒池,如果有客戶端鏈接就創建一個執行緒與之通信 ExecutorService executorService = Executors.newCachedThreadPool(); // 2.創建ServerSocket ServerSocket serverSocket = new ServerSocket(9999); System.out.println("服務器已啟動"); while (true) { // 3.監聽客戶端 Socket socket = serverSocket.accept(); System.out.println("有客戶端鏈接"); executorService.execute(new Runnable() { @Override public void run() { handle(socket); } }); } } private static void handle(Socket socket) { try { System.out.println("執行緒ID:" + Thread.currentThread().getId() + ",執行緒名稱:" + Thread.currentThread().getName()); // 從連接中取出輸入流 InputStream inputStream = socket.getInputStream(); byte[] b = new byte[1024]; int read = inputStream.read(b); System.out.println("客戶端" + new String(b, 0, read)); // 鏈接中取出輸出流并回話 OutputStream outputStream = socket.getOutputStream(); outputStream.write("沒有".getBytes()); } catch (Exception e) { e.printStackTrace(); } finally { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } -
客戶端代碼
/** * 客戶端 * * @name: ClientDemo * @author: terwer * @date: 2022-04-17 15:30 **/ public class ClientDemo { public static void main(String[] args) throws IOException { while (true) { // 1.創建客戶端socket Socket s = new Socket("127.0.0.1", 9999); // 2.從連接中獲取輸出流并發送訊息 OutputStream os = s.getOutputStream(); System.out.println("請輸入:"); Scanner sc = new Scanner(System.in); String msg = sc.nextLine(); os.write(msg.getBytes()); // 3.從連接中取出輸入流并接受會話 InputStream is = s.getInputStream(); byte[] b = new byte[1024]; // 下面寫法錯了 // int read = is.read(); // 應該是 int read = is.read(b); System.out.println("老板說:" + new String(b, 0, read).trim()); s.close(); } } }
IO模型
IO模型說明
-
簡單理解:用什么樣的通道進行資料的發送和接收,在很大程度上決定了程式通信的性能,
-
Java支持三種網路編程模型I/O模式:BIO(同步阻塞)、NIO(同步非阻塞)、AIO(異步非阻塞)
阻塞與非阻塞
指的是網路IO的執行緒是否處于阻塞或者等待狀態
執行緒訪問資源,該資源是否準備就緒的一種處理方式

同步和異步
指的是資料的請求方式,同步和異步是請求資料的一種方式,

BIO(同步阻塞)
Java BIO就是傳統的socket編程
BIO(blocking IO):同步阻塞,服務器實作方式為一個鏈接一個執行緒,即客戶端有一個鏈接時,服務端就要啟動一個執行緒進行處理,如果這個鏈接不作任何事情,會造成不必要的執行緒開銷,可以通過執行緒池改善,實作多個客戶端鏈接服務器,
作業機制

生活中的例子:

BIO的問題分析
- 每個請求都要創建獨立的執行緒,與對應的客戶端進行read,業務處理,資料write
- 并發量大的時候,需要創建大量的執行緒來處理鏈接,系統資源占用較大
- 鏈接建立后,如果當前執行緒沒有資料可讀,執行緒就阻塞在read上,造成執行緒資源浪費
NIO(同步非阻塞)
同步非阻塞,服務器實作模式為一個執行緒處理多個請求(鏈接),客戶端發送的鏈接請求會注冊到多路復用器上,多路復用器輪訓到鏈接有IO請求就進行處理,

生活中的例子:

AIO(異步非阻塞)
AIO引入了異步通道的概念,采用了Proactor模式,簡化了程式撰寫,有效的請求才啟動執行緒,
他的特點是先由作業系統完成后才通知服務端啟動執行緒去處理,一般適用于連接數較多且連接時間較長的應用,
Proactor模式是一個訊息異步通知的模式,Proactor通知的不是就緒事件,而是操作完成事件,這也是作業系統異步IO的主要模型,
https://www.zhihu.com/question/26943938
生活中的例子:

BIO、NIO、AIO的適用場景分析
- BIO(同步阻塞模式)適用于連接數比較小,且固定的架構,對服務器資源的要求比較高,并發局限于應用中,jdk1.4以前的唯一選擇,代碼容易理解,
- NIO(同步非阻塞模式)適用于鏈接數目多且鏈接比較短(輕操作)的架構,比如聊天服務器、彈幕系統、服務器之間的通訊等,編程比較復雜,jdk1.4開始支持,
- AIO(異步非阻塞模式)適用于連接數目比較多并且連接時間比較長(重操作)的架構,比如相冊服務器,充分呼叫OS參與并發操作,編程比較復雜,jdk1.7開始支持,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/469672.html
標籤:其他
上一篇:C++實體1--通訊錄管理系統
下一篇:Jave-Maven詳解
