java的nio之:java的bio流下實現的socket伺服器同步阻塞模型和socket的偽非同步的socket伺服器的通訊模型
同步I/O模型的弊端
===>每一個執行緒的建立都會消耗服務端記憶體,當大量請求進來,會耗盡記憶體,導致服務當機
偽非同步I/O的弊端分析
===>當對Socket的輸入流進行讀取操作的時候,它會一直阻塞下去,知道發生如下三件事情
(1)有資料可讀
(2)可用資料已經讀取完畢
(3)發生空指標或者I/O異常
===>這意味著當對方傳送請求或應答訊息比較緩慢,或者網路傳輸比較慢時候,讀取輸入流的一方的通訊執行緒將被長時間阻塞。在阻塞期間,其他接入的訊息只能在訊息佇列中排隊。
===>偽非同步I/O實際上僅僅只是對之前I/O執行緒模型的一個簡單優化,它無法從根本上解決同步I/O導致的通訊執行緒阻塞問題,下面我們簡單分析下如果通訊對方返回應答時間過長,會引起的級聯鼓掌。
(1)服務端處理緩慢,返回應答訊息耗費60s,平時只需要10ms
(2)採用偽非同步I/O執行緒正在讀取故障服務節點的響應,由於讀取輸入流是阻塞的。因此,它將會被同步阻塞60s
(3)假如所有的可用執行緒都被故障伺服器阻塞,那後續所有的I/O訊息都將在佇列中排隊。
(4)由於執行緒池採用阻塞佇列實現,當佇列積滿之後,後續入佇列的操作將被阻塞
(5)由於前端只有一個Accptor執行緒接收客戶端接入,它被阻塞線上程池的同步阻塞佇列之後,新的客戶端請求訊息將被拒絕,客戶端會發生大量的連線超時。
(6)由於幾乎所有的連結都超時,呼叫者會認為系統崩潰,無法接收新的請求訊息。
【一】同步阻塞I/O服務端通訊模型
第一:socket同步阻塞伺服器的啟動
1 package com.yeepay.sxf.testbio; 2 3 import java.io.IOException; 4 import java.net.ServerSocket; 5 import java.net.Socket; 6 7 /** 8 * 時間伺服器 9 * 基於同步阻塞I/O實現的伺服器模型 10 * @author sxf 11 * 12 */ 13 public class TimerServer { 14 15 /** 16 * 啟動timerServer伺服器 17 */ 18 public void init(){ 19 int port=8000; 20 //建立Socket服務 21 ServerSocket server=null; 22 try { 23 server=new ServerSocket(port); 24 System.out.println("TimerServer.init()===>the time server is start in port"+port); 25 Socket socket=null; 26 while(true){ 27 //獲取一次socket請求 28 socket=server.accept(); 29 //啟動一個新執行緒處理socket請求 30 new Thread(new TimerServerHandler(socket)).start(); 31 } 32 } catch (IOException e) { 33 e.printStackTrace(); 34 }finally{ 35 if(server!=null){ 36 try { 37 server.close(); 38 } catch (IOException e) { 39 // TODO Auto-generated catch block 40 e.printStackTrace(); 41 } 42 } 43 server=null; 44 } 45 46 } 47 48 49 public static void main(String[] args) { 50 //啟動timerServer服務 51 TimerServer timerServer=new TimerServer(); 52 timerServer.init(); 53 } 54 }
第二:soket伺服器接收到請求的處理類
1 package com.yeepay.sxf.testbio; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.PrintWriter; 7 import java.net.Socket; 8 import java.util.Date; 9 10 /** 11 * 時間伺服器接受socket請求的處理類 12 * @author sxf 13 * 繼承Runnable介面的執行緒類 14 * 15 */ 16 public class TimerServerHandler implements Runnable { 17 18 private Socket socket; 19 20 public TimerServerHandler(Socket socket) { 21 this.socket=socket; 22 } 23 24 /** 25 * 處理socket請求的執行緒體 26 */ 27 @Override 28 public void run() { 29 BufferedReader in=null; 30 PrintWriter out=null; 31 try { 32 //獲取請求的輸入流 33 in=new BufferedReader(new InputStreamReader(this.socket.getInputStream())); 34 //獲取響應請求的輸出流 35 out=new PrintWriter(this.socket.getOutputStream(),true); 36 37 String currentTime=null; 38 String body=null; 39 //讀取請求輸入流的內容獲取請求資訊 40 while(true){ 41 body=in.readLine(); 42 if(body==null){ 43 break; 44 } 45 //列印請求資訊 46 System.out.println("TimerServerHandler.run()==>the time server receive order:"+body); 47 48 //處理請求資訊 49 if("shangxiaofei".equals(body)){ 50 currentTime=new Date(System.currentTimeMillis()).toString(); 51 }else{ 52 currentTime="you is not get time"; 53 } 54 //響應請求資訊 55 out.println(currentTime); 56 } 57 58 } catch (IOException e) { 59 e.printStackTrace(); 60 }finally{ 61 if(in!=null){ 62 try { 63 in.close(); 64 } catch (IOException e) { 65 // TODO Auto-generated catch block 66 e.printStackTrace(); 67 } 68 } 69 70 if(out!=null){ 71 out.close(); 72 } 73 74 if(this.socket!=null){ 75 try { 76 socket.close(); 77 } catch (IOException e) { 78 // TODO Auto-generated catch block 79 e.printStackTrace(); 80 } 81 } 82 83 this.socket=null; 84 } 85 86 87 88 89 } 90 91 }
第三:向socket伺服器傳送請求
1 package com.yeepay.sxf.testbio; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.PrintWriter; 7 import java.net.Socket; 8 9 /** 10 * 建立一個客戶端請求 11 * @author sxf 12 * 13 */ 14 public class TimerClient { 15 16 17 18 public static void main(String[] args) { 19 int port=8000; 20 Socket socket=null; 21 BufferedReader in=null; 22 PrintWriter out=null; 23 try { 24 socket=new Socket("127.0.0.1",port); 25 in=new BufferedReader(new InputStreamReader(socket.getInputStream())); 26 out=new PrintWriter(socket.getOutputStream(),true); 27 //傳送請求 28 out.println("shangxiaofei!="); 29 System.out.println("TimerClient.main()send order to server success"); 30 31 //等待伺服器響應 32 String resp=in.readLine(); 33 System.out.println("TimerClient.main(Now is:)"+resp); 34 } catch (Exception e) { 35 // TODO Auto-generated catch block 36 e.printStackTrace(); 37 }finally{ 38 if(out!=null){ 39 out.close(); 40 out=null; 41 } 42 if(in !=null){ 43 try { 44 in.close(); 45 } catch (IOException e) { 46 // TODO Auto-generated catch block 47 e.printStackTrace(); 48 } 49 in=null; 50 } 51 52 if(socket!=null){ 53 try { 54 socket.close(); 55 } catch (IOException e) { 56 // TODO Auto-generated catch block 57 e.printStackTrace(); 58 } 59 } 60 } 61 } 62 63 }
【二】同步阻塞I/O服務端通訊模型構造的偽非同步通訊模型
一:偽非同步socket服務端啟動(就是在同步的基礎上使用了執行緒池)
1 package com.yeepay.sxf.testbio; 2 3 import java.io.IOException; 4 import java.net.ServerSocket; 5 import java.net.Socket; 6 7 /** 8 * 時間伺服器 9 * 基於同步阻塞I/O實現的伺服器模型 10 * @author sxf 11 * 12 */ 13 public class TimerServer { 14 15 /** 16 * 啟動timerServer伺服器 17 */ 18 public void init(){ 19 int port=8000; 20 //建立Socket服務 21 ServerSocket server=null; 22 try { 23 server=new ServerSocket(port); 24 System.out.println("TimerServer.init()===>the time server is start in port"+port); 25 Socket socket=null; 26 //建立處理socket請求的執行緒池 27 TimerServerHandlerExcetorPool pool=new TimerServerHandlerExcetorPool(50, 10000); 28 29 while(true){ 30 //獲取一次socket請求 31 socket=server.accept(); 32 //將請求任務提交到執行緒池處理 33 pool.execute(new TimerServerHandler(socket)); 34 } 35 } catch (IOException e) { 36 e.printStackTrace(); 37 }finally{ 38 if(server!=null){ 39 try { 40 server.close(); 41 } catch (IOException e) { 42 // TODO Auto-generated catch block 43 e.printStackTrace(); 44 } 45 } 46 server=null; 47 } 48 49 } 50 51 52 public static void main(String[] args) { 53 //啟動timerServer服務 54 TimerServer timerServer=new TimerServer(); 55 timerServer.init(); 56 } 57 }
二:偽非同步socket服務處理socket請求的執行緒池
1 package com.yeepay.sxf.testbio; 2 3 import java.util.concurrent.ArrayBlockingQueue; 4 import java.util.concurrent.ExecutorService; 5 import java.util.concurrent.ThreadPoolExecutor; 6 import java.util.concurrent.TimeUnit; 7 /** 8 * 處理socket伺服器接收到的socket請求的執行緒池 9 * @author sxf 10 * 11 */ 12 public class TimerServerHandlerExcetorPool { 13 14 private ExecutorService executorService; 15 16 /** 17 * 初始化執行緒池 18 * @param maxPoolSize 19 * @param queueSize 20 */ 21 public TimerServerHandlerExcetorPool(int maxPoolSize,int queueSize){ 22 executorService=new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), maxPoolSize, 120L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(queueSize)); 23 } 24 25 /** 26 * 提交到執行緒池,執行socket請求任務 27 * @param runnable 28 */ 29 public void execute(Runnable runnable){ 30 executorService.execute(runnable); 31 } 32 33 }
三:處理請求的Handler類(執行緒類)
1 package com.yeepay.sxf.testbio; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.PrintWriter; 7 import java.net.Socket; 8 import java.util.Date; 9 10 /** 11 * 時間伺服器接受socket請求的處理類 12 * @author sxf 13 * 繼承Runnable介面的執行緒類 14 * 15 */ 16 public class TimerServerHandler implements Runnable { 17 18 private Socket socket; 19 20 public TimerServerHandler(Socket socket) { 21 this.socket=socket; 22 } 23 24 /** 25 * 處理socket請求的執行緒體 26 */ 27 @Override 28 public void run() { 29 BufferedReader in=null; 30 PrintWriter out=null; 31 try { 32 //獲取請求的輸入流 33 in=new BufferedReader(new InputStreamReader(this.socket.getInputStream())); 34 //獲取響應請求的輸出流 35 out=new PrintWriter(this.socket.getOutputStream(),true); 36 37 String currentTime=null; 38 String body=null; 39 //讀取請求輸入流的內容獲取請求資訊 40 while(true){ 41 body=in.readLine(); 42 if(body==null){ 43 break; 44 } 45 //列印請求資訊 46 System.out.println("TimerServerHandler.run()==>the time server receive order:"+body); 47 48 //處理請求資訊 49 if("shangxiaofei".equals(body)){ 50 currentTime=new Date(System.currentTimeMillis()).toString(); 51 }else{ 52 currentTime="you is not get time"; 53 } 54 //響應請求資訊 55 out.println(currentTime); 56 } 57 58 } catch (IOException e) { 59 e.printStackTrace(); 60 }finally{ 61 if(in!=null){ 62 try { 63 in.close(); 64 } catch (IOException e) { 65 // TODO Auto-generated catch block 66 e.printStackTrace(); 67 } 68 } 69 70 if(out!=null){ 71 out.close(); 72 } 73 74 if(this.socket!=null){ 75 try { 76 socket.close(); 77 } catch (IOException e) { 78 // TODO Auto-generated catch block 79 e.printStackTrace(); 80 } 81 } 82 83 this.socket=null; 84 } 85 86 87 88 89 } 90 91 }
四:客戶端傳送請求
1 package com.yeepay.sxf.testbio; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.PrintWriter; 7 import java.net.Socket; 8 9 /** 10 * 建立一個客戶端請求 11 * @author sxf 12 * 13 */ 14 public class TimerClient { 15 16 17 18 public static void main(String[] args) { 19 int port=8000; 20 Socket socket=null; 21 BufferedReader in=null; 22 PrintWriter out=null; 23 try { 24 socket=new Socket("127.0.0.1",port); 25 in=new BufferedReader(new InputStreamReader(socket.getInputStream())); 26 out=new PrintWriter(socket.getOutputStream(),true); 27 //傳送請求 28 out.println("shangxiaofei!="); 29 System.out.println("TimerClient.main()send order to server success"); 30 31 //等待伺服器響應 32 String resp=in.readLine(); 33 System.out.println("TimerClient.main(Now is:)"+resp); 34 } catch (Exception e) { 35 // TODO Auto-generated catch block 36 e.printStackTrace(); 37 }finally{ 38 if(out!=null){ 39 out.close(); 40 out=null; 41 } 42 if(in !=null){ 43 try { 44 in.close(); 45 } catch (IOException e) { 46 // TODO Auto-generated catch block 47 e.printStackTrace(); 48 } 49 in=null; 50 } 51 52 if(socket!=null){ 53 try { 54 socket.close(); 55 } catch (IOException e) { 56 // TODO Auto-generated catch block 57 e.printStackTrace(); 58 } 59 } 60 } 61 } 62 63 }
相關文章
- Thinking in Java--使用NIO實現非阻塞Socket通訊2020-04-04ThinkingJava
- socket阻塞與非阻塞,同步與非同步、I/O模型2023-05-18非同步模型
- Java 和 Python 之間的 Socket 通訊2020-09-15JavaPython
- Java基礎(Socket通訊和NIO)2020-12-13Java
- Java Socket 之 NIO2018-05-03Java
- 如何解讀 Java IO、NIO 中的同步阻塞與同步非阻塞?2020-09-03Java
- 從linux原始碼看socket的阻塞和非阻塞2020-06-04Linux原始碼
- 從 Linux 原始碼看 socket 的阻塞和非阻塞2018-04-12Linux原始碼
- Java的Socket通訊簡單例項2021-10-27Java單例
- IO通訊模型(二)同步非阻塞模式NIO(NonBlocking IO)2019-11-08模型模式BloC
- socket通訊的建立2020-10-11
- Netty實現的一個非同步Socket程式碼2019-03-25Netty非同步
- Java網路程式設計和NIO詳解1:JAVA 中原生的 socket 通訊機制2019-11-11Java程式設計
- 簡單的Socket通訊2018-08-18
- JAVA - 基於Socket的多執行緒通訊2020-08-08Java執行緒
- c#實現最簡單的socket通訊2020-10-03C#
- socket 完成簡單的通訊2020-05-07
- TCP socket和web socket的區別2019-02-24TCPWeb
- C# 實現socket通訊程式(伺服器端)2019-06-20C#伺服器
- epoll+socket實現 socket併發 linux伺服器2018-12-28Linux伺服器
- Java非阻塞I/O模型之NIO說明2021-07-04Java模型
- Socket搭建即時通訊伺服器2018-11-16伺服器
- 談談對不同I/O模型的理解 (阻塞/非阻塞IO,同步/非同步IO)2020-11-10模型非同步
- socket 實現的 web 伺服器在 Windows 下的讀寫問題2019-04-14Web伺服器Windows
- 詳解Java Socket的工作機制2018-08-12Java
- socket通訊2020-10-17
- Socket Server 的 N 種併發模型彙總2020-04-06Server模型
- Socket Server的N種併發模型彙總2020-04-06Server模型
- 同步、非同步、阻塞、非阻塞的區別2018-12-03非同步
- socket 的使用2019-06-15
- Socket最簡單的客戶端與服務端通訊-Java2022-11-12客戶端服務端Java
- 從同步原語看非阻塞同步以及Java中的應用2019-06-15Java
- IO - 同步 非同步 阻塞 非阻塞的區別2018-05-12非同步
- java socket例子2020-04-05Java
- 實現伺服器和客戶端資料互動,Java Socket有妙招2021-10-26伺服器客戶端Java
- java同步非阻塞IO2018-07-02Java
- Socket程式設計模型2024-06-03程式設計模型
- linux非阻塞式socket程式設計之select()用法2018-05-31Linux程式設計
- Android Socket 通訊2018-07-14Android