java的nio之:java的bio流下實現的socket伺服器同步阻塞模型和socket的偽非同步的socket伺服器的通訊模型

Love Lenka發表於2016-08-31

同步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 }
View Code

第二: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 }
View Code

第三:向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 }
View Code

 

 

【二】同步阻塞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 }
View Code

二:偽非同步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 }
View Code

三:處理請求的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 }
View Code

四:客戶端傳送請求

 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 }
View Code

 

相關文章