同步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