• BIO编程


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

      代码实现:

      server端代码:

     1 import java.io.IOException;
     2 import java.net.ServerSocket;
     3 import java.net.Socket;
     4 
     5 
     6 public class Server {
     7 
     8     final static int PROT = 8765;
     9     
    10     public static void main(String[] args) {
    11         
    12         ServerSocket server = null;
    13         try {
    14             server = new ServerSocket(PROT);
    15             System.out.println(" server start .. ");
    16             while (true) {
    17                 //进行阻塞
    18                 Socket socket = server.accept();
    19                 //新建一个线程执行客户端的任务
    20                 new Thread(new ServerHandler(socket)).start();
    21             }
    22             
    23         } catch (Exception e) {
    24             e.printStackTrace();
    25         } finally {
    26             if(server != null){
    27                 try {
    28                     server.close();
    29                 } catch (IOException e) {
    30                     e.printStackTrace();
    31                 }
    32             }
    33             server = null;
    34         }
    35         
    36         
    37         
    38     }
    Server 类
     1 import java.io.BufferedReader;
     2 import java.io.IOException;
     3 import java.io.InputStreamReader;
     4 import java.io.PrintWriter;
     5 import java.net.Socket;
     6 
     7 public class ServerHandler implements Runnable{
     8 
     9     private Socket socket ;
    10     
    11     public ServerHandler(Socket socket){
    12         this.socket = socket;
    13     }
    14     
    15     @Override
    16     public void run() {
    17         BufferedReader in = null;
    18         PrintWriter out = null;
    19         try {
    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("服务器端回响的应数据.");
    28             }
    29             
    30         } catch (Exception e) {
    31             e.printStackTrace();
    32         } finally {
    33             if(in != null){
    34                 try {
    35                     in.close();
    36                 } catch (IOException e) {
    37                     e.printStackTrace();
    38                 }
    39             }
    40             if(out != null){
    41                 try {
    42                     out.close();
    43                 } catch (Exception e) {
    44                     e.printStackTrace();
    45                 }
    46             }
    47             if(socket != null){
    48                 try {
    49                     socket.close();
    50                 } catch (IOException e) {
    51                     e.printStackTrace();
    52                 }
    53             }
    54             socket = null;
    55         }
    56         
    57         
    58     }
    59 
    60 }
    ServerHandler类,业务处理类

      client端代码:

     1 import java.io.BufferedReader;
     2 import java.io.IOException;
     3 import java.io.InputStreamReader;
     4 import java.io.PrintWriter;
     5 import java.net.Socket;
     6 
     7 public class Client {
     8 
     9     final static String ADDRESS = "127.0.0.1";
    10     final static int PORT = 8765;
    11     
    12     public static void main(String[] args) {
    13         
    14         Socket socket = null;
    15         BufferedReader in = null;
    16         PrintWriter out = null;
    17         
    18         try {
    19             socket = new Socket(ADDRESS, PORT);
    20             in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    21             out = new PrintWriter(socket.getOutputStream(), true);
    22             
    23             //向服务器端发送数据
    24             out.println("接收到客户端的请求数据...");
    25             out.println("接收到客户端的请求数据1111...");
    26             String response = in.readLine();
    27             System.out.println("Client: " + response);
    28             
    29         } catch (Exception e) {
    30             e.printStackTrace();
    31         } finally {
    32             if(in != null){
    33                 try {
    34                     in.close();
    35                 } catch (IOException e) {
    36                     e.printStackTrace();
    37                 }
    38             }
    39             if(out != null){
    40                 try {
    41                     out.close();
    42                 } catch (Exception e) {
    43                     e.printStackTrace();
    44                 }
    45             }
    46             if(socket != null){
    47                 try {
    48                     socket.close();
    49                 } catch (IOException e) {
    50                     e.printStackTrace();
    51                 }
    52             }
    53             socket = null;
    54         }
    55     }
    56 }
    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端线程数过多时宕机的问题,但是依然没有解决阻塞的问题。依然会出现请求过多时,前台等待超时的问题。

  • 相关阅读:
    重构的体会——类属性优先移动
    jQuery实现无限循环滚动公告
    jquery菜单左右翻屏效果
    44种IE css bug实例测试总结
    IE6不支持position:fixed的解决方法
    DedeCMS会员排行调用代码,实现连接到会员空间
    程序员们 不要想一辈子靠技术混饭吃
    Load JSON data with jQuery, PHP and MySQL
    mysql 实现行号的方法——如何获取当前记录所在行号
    jQuery精仿手机上的翻牌效果菜单
  • 原文地址:https://www.cnblogs.com/liyasong/p/BIO.html
Copyright © 2020-2023  润新知