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

浙公网安备 33010602011771号