Java AIO 实例(转)

转载:http://m.blog.csdn.net/article/details?id=51512200

AIO异步非阻塞IO实例:客户端发送数学表达式,经过服务端接收计算后返回客户端。

 

1、服务端

包括,Server、ServerHandler、ServerWriteHandler、ServerReadHandler、AcceptHandler、Calculator

   1.1 启动程序:

 1 public class Server {  
 2   
 3     private static int DEFAULT_PORT = 12345;  
 4     private static AsyncServerHandler serverHandle;  
 5     public volatile static long clientCount = 0;  
 6     public static void start(){  
 7         start(DEFAULT_PORT);  
 8     }  
 9     public static synchronized void start(int port){  
10         if(serverHandle!=null)  
11             return;  
12         serverHandle = new AsyncServerHandler(port);  
13         new Thread(serverHandle,"Server").start();  
14     }  
15     public static void main(String[] args){  
16         Server.start();  
17     }  
18   
19 }  

1.2 AsyncServerHandler

 1 import java.io.IOException;  
 2 import java.net.InetSocketAddress;  
 3 import java.nio.channels.AsynchronousServerSocketChannel;  
 4 import java.util.concurrent.CountDownLatch;  
 5   
 6 public class AsyncServerHandler implements Runnable{  
 7     public CountDownLatch latch;  
 8     public AsynchronousServerSocketChannel channel;  
 9     public AsyncServerHandler(int port) {  
10         try {  
11             //创建服务端通道  
12             channel = AsynchronousServerSocketChannel.open();  
13             //绑定端口  
14             channel.bind(new InetSocketAddress(port));  
15             System.out.println("服务器已启动,端口号:" + port);  
16         } catch (IOException e) {  
17             e.printStackTrace();  
18         }  
19     }  
20     @Override  
21     public void run() {  
22         //CountDownLatch初始化  
23         //它的作用:在完成一组正在执行的操作之前,允许当前的现场一直阻塞  
24         //此处,让现场在此阻塞,防止服务端执行完成后退出  
25         //也可以使用while(true)+sleep   
26         //生成环境就不需要担心这个问题,以为服务端是不会退出的  
27         latch = new CountDownLatch(1);  
28         //用于接收客户端的连接  
29         channel.accept(this,new AcceptHandler());  
30         try {  
31             latch.await();  
32         } catch (InterruptedException e) {  
33             e.printStackTrace();  
34         }  
35     }  
36 }  

1.3 AcceptHandler

 1 import java.nio.ByteBuffer;  
 2 import java.nio.channels.AsynchronousSocketChannel;  
 3 import java.nio.channels.CompletionHandler;  
 4 //作为handler接收客户端连接  
 5 public class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel, AsyncServerHandler>{  
 6   
 7     @Override  
 8     public void completed(AsynchronousSocketChannel channel, AsyncServerHandler serverHandler) {  
 9         //继续接受其他客户端的请求  
10         Server.clientCount++;  
11         System.out.println("连接的客户端数:" + Server.clientCount);  
12         serverHandler.channel.accept(serverHandler, this);  
13         //创建新的Buffer  
14         ByteBuffer buffer = ByteBuffer.allocate(1024);  
15         //异步读  第三个参数为接收消息回调的业务Handler  
16         channel.read(buffer, buffer, new ServerReadHandler(channel));  
17     }  
18   
19     @Override  
20     public void failed(Throwable exc, AsyncServerHandler serverHandler) {  
21         exc.printStackTrace();  
22         serverHandler.latch.countDown();  
23     }  
24   
25 }

1.4 ServerReadHandler

 1 import java.io.IOException;  
 2 import java.io.UnsupportedEncodingException;  
 3 import java.nio.ByteBuffer;  
 4 import java.nio.channels.AsynchronousSocketChannel;  
 5 import java.nio.channels.CompletionHandler;  
 6   
 7 public class ServerReadHandler implements CompletionHandler<Integer, ByteBuffer> {  
 8     //用于读取半包消息和发送应答  
 9     private AsynchronousSocketChannel channel;  
10     public ServerReadHandler(AsynchronousSocketChannel channel) {  
11             this.channel = channel;  
12     }  
13     //读取到消息后的处理  
14     @Override  
15     public void completed(Integer result, ByteBuffer attachment) {  
16         //flip操作  
17         attachment.flip();  
18         //根据  
19         byte[] message = new byte[attachment.remaining()];  
20         attachment.get(message);  
21         try {  
22             String expression = new String(message, "UTF-8");  
23             System.out.println("服务器收到消息: " + expression);  
24             String calrResult = null;  
25             try{  
26                 calrResult = Calculator.cal(expression).toString();  
27             }catch(Exception e){  
28                 calrResult = "计算错误:" + e.getMessage();  
29             }  
30             //向客户端发送消息  
31             doWrite(calrResult);  
32         } catch (UnsupportedEncodingException e) {  
33             e.printStackTrace();  
34         }  
35     }  
36     //发送消息  
37     private void doWrite(String result) {  
38         byte[] bytes = result.getBytes();  
39         ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);  
40         writeBuffer.put(bytes);  
41         writeBuffer.flip();  
42         //异步写数据 参数与前面的read一样  
43         channel.write(writeBuffer, writeBuffer,new ServerWriteHandler(channel));  
44     }  
45     @Override  
46     public void failed(Throwable exc, ByteBuffer attachment) {  
47         try {  
48             this.channel.close();  
49         } catch (IOException e) {  
50             e.printStackTrace();  
51         }  
52     }  
53 }

  1.5 ServerWriteHandler

 1 import java.io.IOException;  
 2 import java.nio.ByteBuffer;  
 3 import java.nio.channels.AsynchronousSocketChannel;  
 4 import java.nio.channels.CompletionHandler;  
 5   
 6 public class ServerWriteHandler implements CompletionHandler<Integer, ByteBuffer>{  
 7   
 8     private AsynchronousSocketChannel channel;  
 9       
10     public ServerWriteHandler(AsynchronousSocketChannel channel) {  
11             this.channel = channel;  
12     }  
13       
14     @Override  
15     public void completed(Integer result, ByteBuffer buffer) {  
16         //如果没有发送完,就继续发送直到完成  
17         if (buffer.hasRemaining())  
18             channel.write(buffer, buffer, this);  
19         else{  
20             //创建新的Buffer  
21             ByteBuffer readBuffer = ByteBuffer.allocate(1024);  
22             //异步读  第三个参数为接收消息回调的业务Handler  
23             channel.read(readBuffer, readBuffer, new ServerReadHandler(channel));  
24         }  
25     }  
26     @Override  
27     public void failed(Throwable exc, ByteBuffer attachment) {  
28         try {  
29             channel.close();  
30         } catch (IOException e) {  
31         }  
32     }  
33   
34 }

  1.6 Calculator

 1 import javax.script.ScriptEngine;  
 2 import javax.script.ScriptEngineManager;  
 3 import javax.script.ScriptException;  
 4   
 5 public class Calculator {  
 6     private final static ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");  
 7     public static Object cal(String expression) throws ScriptException{  
 8         return jse.eval(expression);  
 9     }  
10 }  

2、客服端

包括 Client、ClientHandler、ClientWriteHandler、ClientReadHandler 

  2.1 启动器

 1 import java.util.Scanner;  
 2   
 3 public class Client {  
 4   
 5     private static String DEFAULT_HOST = "127.0.0.1";  
 6     private static int DEFAULT_PORT = 12345;  
 7     private static AsyncClientHandler clientHandle;  
 8     public static void start(){  
 9         start(DEFAULT_HOST,DEFAULT_PORT);  
10     }  
11     public static synchronized void start(String ip,int port){  
12         if(clientHandle!=null)  
13             return;  
14         clientHandle = new AsyncClientHandler(ip,port);  
15         new Thread(clientHandle,"Client").start();  
16     }  
17     //向服务器发送消息  
18     public static boolean sendMsg(String msg) throws Exception{  
19         if(msg.equals("q")) return false;  
20         clientHandle.sendMsg(msg);  
21         return true;  
22     }  
23     @SuppressWarnings("resource")  
24     public static void main(String[] args) throws Exception{  
25         Client.start();  
26         System.out.println("请输入请求消息:");  
27         Scanner scanner = new Scanner(System.in);  
28         while(Client.sendMsg(scanner.nextLine()));  
29     }  
30 } 

 2.2 AsyncClientHandler

 1 import java.io.IOException;  
 2 import java.net.InetSocketAddress;  
 3 import java.nio.ByteBuffer;  
 4 import java.nio.channels.AsynchronousSocketChannel;  
 5 import java.nio.channels.CompletionHandler;  
 6 import java.util.concurrent.CountDownLatch;  
 7   
 8 public class AsyncClientHandler implements CompletionHandler<Void, AsyncClientHandler>, Runnable{  
 9     private AsynchronousSocketChannel clientChannel;  
10     private String host;  
11     private int port;  
12     private CountDownLatch latch;  
13     public AsyncClientHandler(String host, int port) {  
14         this.host = host;  
15         this.port = port;  
16         try {  
17             //创建异步的客户端通道  
18             clientChannel = AsynchronousSocketChannel.open();  
19         } catch (IOException e) {  
20             e.printStackTrace();  
21         }  
22     }  
23     @Override  
24     public void run() {  
25         //创建CountDownLatch等待  
26         latch = new CountDownLatch(1);  
27         //发起异步连接操作,回调参数就是这个类本身,如果连接成功会回调completed方法  
28         clientChannel.connect(new InetSocketAddress(host, port), this, this);  
29         try {  
30             latch.await();  
31         } catch (InterruptedException e1) {  
32             e1.printStackTrace();  
33         }  
34         try {  
35             clientChannel.close();  
36         } catch (IOException e) {  
37             e.printStackTrace();  
38         }  
39     }  
40     //连接服务器成功  
41     //意味着TCP三次握手完成  
42     @Override  
43     public void completed(Void result, AsyncClientHandler attachment) {  
44         System.out.println("客户端成功连接到服务器...");  
45     }  
46     //连接服务器失败  
47     @Override  
48     public void failed(Throwable exc, AsyncClientHandler attachment) {  
49         System.err.println("连接服务器失败...");  
50         exc.printStackTrace();  
51         try {  
52             clientChannel.close();  
53             latch.countDown();  
54         } catch (IOException e) {  
55             e.printStackTrace();  
56         }  
57     }  
58     //向服务器发送消息  
59     public void sendMsg(String msg){  
60         byte[] req = msg.getBytes();  
61         ByteBuffer writeBuffer = ByteBuffer.allocate(req.length);  
62         writeBuffer.put(req);  
63         writeBuffer.flip();  
64         //异步写  
65         clientChannel.write(writeBuffer, writeBuffer,new ClientWriteHandler(clientChannel, latch));  
66     }  
67 }

2.3 ClientWriteHandler

 1 import java.io.IOException;  
 2 import java.nio.ByteBuffer;  
 3 import java.nio.channels.AsynchronousSocketChannel;  
 4 import java.nio.channels.CompletionHandler;  
 5 import java.util.concurrent.CountDownLatch;  
 6   
 7 public class ClientWriteHandler implements CompletionHandler<Integer, ByteBuffer>{  
 8     private AsynchronousSocketChannel clientChannel;  
 9     private CountDownLatch latch;  
10     public ClientWriteHandler(AsynchronousSocketChannel clientChannel,CountDownLatch latch) {  
11         this.clientChannel = clientChannel;  
12         this.latch = latch;  
13     }  
14     @Override  
15     public void completed(Integer result, ByteBuffer buffer) {  
16         //完成全部数据的写入  
17         if (buffer.hasRemaining()) {  
18             clientChannel.write(buffer, buffer, this);  
19         }  
20         else {  
21             //读取数据  
22             ByteBuffer readBuffer = ByteBuffer.allocate(1024);  
23             clientChannel.read(readBuffer,readBuffer,new ClientReadHandler(clientChannel, latch));  
24         }  
25     }  
26     @Override  
27     public void failed(Throwable exc, ByteBuffer attachment) {  
28         System.err.println("数据发送失败...");  
29         try {  
30             clientChannel.close();  
31             latch.countDown();  
32         } catch (IOException e) {  
33         }  
34     }  
35 } 

2.4 ClientReadHandler

 1 import java.io.IOException;  
 2 import java.io.UnsupportedEncodingException;  
 3 import java.nio.ByteBuffer;  
 4 import java.nio.channels.AsynchronousSocketChannel;  
 5 import java.nio.channels.CompletionHandler;  
 6 import java.util.concurrent.CountDownLatch;  
 7   
 8 public class ClientReadHandler implements CompletionHandler<Integer, ByteBuffer> {  
 9     private AsynchronousSocketChannel clientChannel;  
10     private CountDownLatch latch;  
11     public ClientReadHandler(AsynchronousSocketChannel clientChannel,CountDownLatch latch) {  
12         this.clientChannel = clientChannel;  
13         this.latch = latch;  
14     }  
15     @Override  
16     public void completed(Integer result,ByteBuffer buffer) {  
17         buffer.flip();  
18         byte[] bytes = new byte[buffer.remaining()];  
19         buffer.get(bytes);  
20         String body;  
21         try {  
22             body = new String(bytes,"UTF-8");  
23             System.out.println("客户端收到结果:"+ body);  
24         } catch (UnsupportedEncodingException e) {  
25             e.printStackTrace();  
26         }  
27     }  
28     @Override  
29     public void failed(Throwable exc,ByteBuffer attachment) {  
30         System.err.println("数据读取失败...");  
31         try {  
32             clientChannel.close();  
33             latch.countDown();  
34         } catch (IOException e) {  
35         }  
36     }  
37 } 

3、执行结果

 1 服务器已启动,端口号:12345  
 2 请输入请求消息:  
 3 客户端成功连接到服务器...  
 4 连接的客户端数:1  
 5 123456+789+456  
 6 服务器收到消息: 123456+789+456  
 7 客户端收到结果:124701  
 8 9526*56  
 9 服务器收到消息: 9526*56  
10 客户端收到结果:533456  

 

posted @ 2021-05-11 17:53  莫待樱开春来踏雪觅芳踪  阅读(233)  评论(0)    收藏  举报