BIO编程

时间:2024-01-27 15:32:29

  在实际的工作开发中,传统的模型有client/service模型。client端和service端要进行通信的话,有一种套接字的方式。传统的socket编程,包含一个socket服务端和一到多个socket客户端。在连接过程中,sokcetServer 绑定一个端口进行监听。client端通过ip地址和端口号对服务进行访问。在服务进入到service端后,service端新建一个线程。线程对请求进行相应的处理,处理完毕后,将处理结果返回给client端。在处理过程中,连接client阻塞。

  代码实现:

  server端代码:

  Server 类

  ServerHandler类,业务处理类

  client端代码:

  Client类

  优点:传统的BIO模型进行通信,代码可读性比较强,理解容易。运行中,server端通过主线程监听accpet()方法阻塞式获取server的消息。

  缺点:该模型最大的问题是,每一个client端访问都对应一个后台的线程,使得系统不具备弹性伸缩能力。一旦client请求过多,线程数会迅速膨胀,系统性能会急剧下降,导致堆栈溢出,进程宕机等问题的发生。

  为了改进线程数过多,导致系统宕机的问题,同时也为了解决创建线程的消耗问题。后来又演进出了一种通过线程池或者消息队列实现1个或者多个线程处理N个客户端的模型,由于它的底层通信机制依然使用同步阻塞IO,所以被称为 “伪异步”。其原理就是在原来的service上新增一个线程池,将处理业务的线程通过线程池进行管理。如果线程数量到达上限时,将请求先存入queue中进行缓冲。具体代码如下:

  client端代码不变。

  server端:  

 1 import java.io.BufferedReader;
 2 import java.io.PrintWriter;
 3 import java.net.ServerSocket;
 4 import java.net.Socket;
 5 
 6 public class Server {
 7 
 8     final static int PORT = 8765;
 9 
10     public static void main(String[] args) {
11         ServerSocket server = null;
12         BufferedReader in = null;
13         PrintWriter out = null;
14         try {
15             server = new ServerSocket(PORT);
16             System.out.println("server start");
17             Socket socket = null;
18             HandlerExecutorPool executorPool = new HandlerExecutorPool(50, 50);
19             while(true){
20                 socket = server.accept();
21                 
22                 executorPool.execute(new ServerHandler(socket));
23                 
24             }
25             
26         } catch (Exception e) {
27             e.printStackTrace();
28         } finally {
29             if(in != null){
30                 try {
31                     in.close();
32                 } catch (Exception e1) {
33                     e1.printStackTrace();
34                 }
35             }
36             if(out != null){
37                 try {
38                     out.close();
39                 } catch (Exception e2) {
40                     e2.printStackTrace();
41                 }
42             }
43             if(server != null){
44                 try {
45                     server.close();
46                 } catch (Exception e3) {
47                     e3.printStackTrace();
48                 }
49             }
50             server = null;                
51         }
52         
53     
54     
55     }
56     
57     
58 }
Server类
 1 import java.util.concurrent.ArrayBlockingQueue;
 2 import java.util.concurrent.ThreadPoolExecutor;
 3 import java.util.concurrent.TimeUnit;
 4 
 5 
 6 public class HandlerExecutorPool {
 7     private ArrayBlockingQueue queue ;
 8     private ThreadPoolExecutor executor;
 9     public HandlerExecutorPool(int maxPoolSize, int queueSize){
10         queue = new ArrayBlockingQueue<Runnable>(queueSize);
11         this.executor = new ThreadPoolExecutor(
12                 5,
13                 maxPoolSize, 
14                 120L, 
15                 TimeUnit.SECONDS,
16                 queue);
17     }
18     
19     public void execute(Runnable task){
20         System.out.println("corePoolSize== "+executor.getCorePoolSize());
21         System.out.println("queuesize=="+queue.size());
22         this.executor.execute(task);
23         
24         System.out.println("当前运行线程== "+executor.getLargestPoolSize());
25         System.out.println("queuesize=="+queue.size());
26     }
27     
28     
29     
30 }
HandlerExecutorPool 线程池缓冲队列类
 1 import java.io.BufferedReader;
 2 import java.io.InputStreamReader;
 3 import java.io.PrintWriter;
 4 import java.net.Socket;
 5 import java.util.concurrent.TimeUnit;
 6 
 7 public class ServerHandler implements Runnable {
 8 
 9     private Socket socket;
10     public ServerHandler (Socket socket){
11         this.socket = socket;
12     }
13     
14     @Override
15     public void run() {
16         BufferedReader in = null;
17         PrintWriter out = null;
18         try {
19             Thread.currentThread().sleep(1000);
20             in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
21             out = new PrintWriter(this.socket.getOutputStream(), true);
22             String body = null;
23             while(true){
24                 body = in.readLine();
25                 if(body == null) break;
26                 System.out.println("Server:" + body);
27                 out.println("Server response");
28             }
29         } catch (Exception e) {
30             e.printStackTrace();
31         } finally {
32             if(in != null){
33                 try {
34                     in.close();
35                 } catch (Exception e1) {
36                     e1.printStackTrace();
37                 }
38             }
39             if(out != null){
40                 try {
41                     out.close();
42                 } catch (Exception e2) {
43                     e2.printStackTrace();
44                 }
45             }
46             if(socket != null){
47                 try {
48                     socket.close();
49                 } catch (Exception e3) {
50                     e3.printStackTrace();
51                 }
52             }
53             socket = null;            
54         }
55         
56         
57     }
58 
59 }
ServerHandler类,业务处理类

  这样改造后,有效的缓解了server端线程数过多时宕机的问题,但是依然没有解决阻塞的问题。依然会出现请求过多时,前台等待超时的问题。