NIO2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。异步通道提供以下两种方式获取操作结果。
1、通过java.util.concurrent.Future 类来表示异步操作的结果;
2、在执行异步操作的时候传入一个java.io.channels。
ComplementHandler接口的实现类作为操作完成的回调。
NIO2.0的异步套接字通道是真正的异步非阻塞I/O,它不需要通过多路复用器(Selector)对注册的通道进行轮询操作即可实现异步读写,从而简化了NIO编程模型。
改造后的代码
server端代码:
1 package com.example.biodemo; 2 3 4 import java.io.*; 5 import java.net.ServerSocket; 6 import java.net.Socket; 7 8 public class TimeServer { 9 public static void main(String[] args) throws IOException { 10 int port = 8092; 11 if (args != null && args.length > 0) { 12 try { 13 port = Integer.valueOf(args[0]); 14 } catch (NumberFormatException e) { 15 port = 8092; 16 } 17 } 18 AsyncTimeServerHandler timeServer = new AsyncTimeServerHandler(port); 19 new Thread(timeServer,"AsychronousTimeServerHandler").start(); 20 21 22 23 // ===================改造代码为AIO将以下内容注释掉================================= 24 25 // 创建多路复用线程类并初始化多路复用器,绑定端口等以及轮询注册功能 26 /* MultiplexerTimeServer timeServer = new MultiplexerTimeServer(port); 27 // 启动多路复用类线程负责轮询多路复用器Selector,IO数据处理等操作 28 new Thread(timeServer, "NIO-MultiplexerTimeSever-001").start();*/ 29 30 // ===================以下内容注释掉================================= 31 32 /* ServerSocket server = null; 33 try { 34 server = new ServerSocket(port); 35 System.out.println("the timeServer is start in port :" + port); 36 Socket socket = null; 37 // 引入线程池start 38 TimeServerHandlerExecutePool singleExecutor = new TimeServerHandlerExecutePool(50,10000); 39 while (true) { 40 socket = server.accept(); 41 // 替换BIO中new Thread(new TimeServerHandler(socket)).start();为下一行代码 42 singleExecutor.execute(new TimeServerHandler(socket)); 43 // 引入线程池end 44 45 } 46 } finally { 47 if (server != null) { 48 System.out.println("the time server close"); 49 server.close(); 50 server = null; 51 } 52 }*/ 53 54 } 55 }
异步时间服务处理器
1 package com.example.biodemo; 2 3 import java.io.IOException; 4 import java.net.InetSocketAddress; 5 import java.nio.channels.AsynchronousServerSocketChannel; 6 import java.util.concurrent.CountDownLatch; 7 8 public class AsyncTimeServerHandler implements Runnable{ 9 private int port; 10 // 添加它作用是在完成一组正在执行的操作之前,允许当前线程一直阻塞 11 CountDownLatch latch; 12 AsynchronousServerSocketChannel asynchronousServerSocketChannel; 13 public AsyncTimeServerHandler(int port) { 14 this.port=port; 15 try { 16 // 创建异步服务套接字通道 17 asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open(); 18 // 绑定监听端口 19 asynchronousServerSocketChannel.bind(new InetSocketAddress(port)); 20 System.out.println("The time server is start in port"+port); 21 } catch (IOException e) { 22 e.printStackTrace(); 23 } 24 } 25 26 @Override 27 public void run() { 28 latch =new CountDownLatch(1); 29 // 接收客户端的连接 30 doAccept(); 31 try { 32 latch.await(); 33 } catch (InterruptedException e) { 34 e.printStackTrace(); 35 } 36 37 } 38 39 private void doAccept() { 40 // AcceptCompletionHandler用于接收accept操作成功的通知消息 41 // accept(A attachment, CompletionHandler<AsynchronousSocketChannel,? super A> handler):接受连接,并为连接绑定一个CompletionHandler处理Socket连接 42 asynchronousServerSocketChannel.accept(this,new AcceptCompletionHandler()); 43 } 44 }
AcceptCompletionHandle
1 package com.example.biodemo; 2 3 import java.nio.ByteBuffer; 4 import java.nio.channels.AsynchronousServerSocketChannel; 5 import java.nio.channels.AsynchronousSocketChannel; 6 import java.nio.channels.CompletionHandler; 7 8 public class AcceptCompletionHandler implements CompletionHandler<AsynchronousSocketChannel,AsyncTimeServerHandler>{ 9 10 @Override 11 public void completed(AsynchronousSocketChannel result, AsyncTimeServerHandler attachment) { 12 //再次让asynchronousServerSocketChannel对象调用accept方法是 13 //调用AsynchronousServerSocketChannel的accept方法后,如果有新的客户端接入, 14 // 系统将回调我们传入的CompletionHandler实例的completed方法,表示新客户端连接成功。 15 // 因为AsynchronousServerSocketChannel可以接受成千上万个客户端,所以需要继续调用它的accept方法, 16 // 接受其他客户端连接,最终形成一个环;每当一个客户端连接成功后,再异步接受新的客户端连接 17 attachment.asynchronousServerSocketChannel.accept(attachment,this); 18 // 据上,链路建立成功,服务端需要接受客户端新请求消息, 19 ByteBuffer buffer = ByteBuffer.allocate(1024); 20 // 调用read方法进行异步读操作 21 result.read(buffer,buffer,new ReadCompletionHandler(result)); 22 } 23 24 @Override 25 public void failed(Throwable exc, AsyncTimeServerHandler attachment) { 26 exc.printStackTrace(); 27 attachment.latch.countDown(); 28 } 29 30 31 }
ReadCompletionHandler
1 package com.example.biodemo; 2 3 import java.io.IOException; 4 import java.io.UnsupportedEncodingException; 5 import java.nio.ByteBuffer; 6 import java.nio.channels.AsynchronousSocketChannel; 7 import java.nio.channels.CompletionHandler; 8 import java.util.Date; 9 10 public class ReadCompletionHandler implements CompletionHandler<Integer,ByteBuffer> { 11 12 private AsynchronousSocketChannel channel; 13 14 public ReadCompletionHandler(AsynchronousSocketChannel channel) { 15 if(this.channel==null){ 16 this.channel=channel; 17 } 18 } 19 20 @Override 21 public void completed(Integer result, ByteBuffer attachment) { 22 attachment.flip(); 23 byte[] body = new byte[attachment.remaining()]; 24 attachment.get(body); 25 try { 26 String req = new String(body,"utf-8"); 27 System.out.println("The time server recerve order : "+req); 28 String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(req)?new Date(System.currentTimeMillis()).toString():"BAD ORDER"; 29 doWriter(currentTime); 30 } catch (UnsupportedEncodingException e) { 31 e.printStackTrace(); 32 } 33 } 34 35 private void doWriter(String currentTime) { 36 if (currentTime != null && currentTime.trim().length() > 0) { 37 byte[] bytes = currentTime.getBytes(); 38 ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length); 39 writeBuffer.put(bytes); 40 writeBuffer.flip(); 41 channel.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() { 42 @Override 43 public void completed(Integer result, ByteBuffer attachment) { 44 //如果没有发送完继续发送 45 if (attachment.hasRemaining()) { 46 channel.write(attachment, attachment, this); 47 } 48 } 49 @Override 50 public void failed(Throwable exc, ByteBuffer attachment) { 51 try { 52 channel.close(); 53 } catch (IOException e) { 54 } 55 } 56 }); 57 } 58 } 59 @Override 60 public void failed(Throwable exc, ByteBuffer attachment) { 61 try { 62 this.channel.close(); 63 } catch (IOException e) { 64 e.printStackTrace(); 65 } 66 } 67 }
客户端的代码
1 package com.example.biodemo; 2 3 import java.io.*; 4 import java.net.Socket; 5 6 public class TimeClient { 7 public static void main(String[] args) { 8 int port = 8092; 9 if (args != null && args.length > 0) { 10 try { 11 port = Integer.valueOf(args[0]); 12 } catch (NumberFormatException ne) { 13 port = 8092; 14 } 15 } 16 new Thread(new AsyncTimeClientHandler("127.0.0.1",port)).start(); 17 18 19 20 // new Thread(new TimeClientHandles("127.0.0.1",port),"TimeClient-001").start(); 21 /* 代码改造注释掉以下代码 22 Socket socket = null; 23 BufferedReader in = null; 24 PrintWriter out = null; 25 try { 26 socket = new Socket("127.0.0.1", port); 27 System.out.println(socket.getInputStream()); 28 in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 29 out = new PrintWriter(socket.getOutputStream(), true); 30 out.println("QUERY TIME ORDER"); 31 System.out.println("send order 2 server succeed."); 32 String resp = in.readLine(); 33 System.out.println("now is :" + resp); 34 } catch (IOException e1) { 35 36 } finally { 37 if (out != null) { 38 out.close(); 39 out = null; 40 } 41 42 if (in != null) { 43 try { 44 in.close(); 45 } catch (IOException e2) { 46 e2.printStackTrace(); 47 } 48 in = null; 49 if (socket != null) { 50 try { 51 socket.close(); 52 } catch (IOException e3) { 53 e3.printStackTrace(); 54 } 55 56 } 57 socket = null; 58 } 59 }*/ 60 } 61 }
AsyncTimeClientHandler
1 package com.example.biodemo; 2 3 import java.io.IOException; 4 import java.io.UnsupportedEncodingException; 5 import java.net.InetSocketAddress; 6 import java.nio.ByteBuffer; 7 import java.nio.channels.AsynchronousSocketChannel; 8 import java.nio.channels.CompletionHandler; 9 import java.util.concurrent.CountDownLatch; 10 11 public class AsyncTimeClientHandler implements CompletionHandler<Void, AsyncTimeClientHandler>, Runnable { 12 private AsynchronousSocketChannel asynchronousSocketChannel; 13 private String host; 14 private int port; 15 private CountDownLatch latch; 16 17 public AsyncTimeClientHandler(String host, int port) { 18 this.host = host == null ? "127.0.0.1" : host; 19 this.port = port; 20 try { 21 asynchronousSocketChannel = AsynchronousSocketChannel.open(); 22 } catch (IOException e) { 23 e.printStackTrace(); 24 } 25 } 26 27 @Override 28 public void run() { 29 latch = new CountDownLatch(1); 30 asynchronousSocketChannel.connect(new InetSocketAddress(host, port), this, this); 31 try { 32 latch.await(); 33 } catch (InterruptedException e) { 34 e.printStackTrace(); 35 } 36 try { 37 asynchronousSocketChannel.close(); 38 } catch (IOException e) { 39 e.printStackTrace(); 40 } 41 } 42 43 44 @Override 45 public void completed(Void result, AsyncTimeClientHandler attachment) { 46 byte[] req = "QUERY TIME ORDER".getBytes(); 47 ByteBuffer writeBuffer = ByteBuffer.allocate(req.length); 48 writeBuffer.put(req); 49 writeBuffer.flip(); 50 asynchronousSocketChannel.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() { 51 @Override 52 public void completed(Integer result, ByteBuffer attachment) { 53 if (attachment.hasRemaining()) { 54 asynchronousSocketChannel.write(attachment, attachment, this); 55 } else { 56 ByteBuffer readBuffer = ByteBuffer.allocate(1024); 57 asynchronousSocketChannel.read(readBuffer, readBuffer, new CompletionHandler<Integer, ByteBuffer>() { 58 @Override 59 public void completed(Integer result, ByteBuffer attachment) { 60 attachment.flip(); 61 byte[] bytes = new byte[attachment.remaining()]; 62 attachment.get(bytes); 63 String body = null; 64 try { 65 body = new String(bytes, "utf-8"); 66 System.out.println(body); 67 System.out.println("Now is :" + body); 68 latch.countDown(); 69 } catch (UnsupportedEncodingException e) { 70 e.printStackTrace(); 71 } 72 73 } 74 75 @Override 76 public void failed(Throwable exc, ByteBuffer attachment) { 77 try { 78 asynchronousSocketChannel.close(); 79 latch.countDown(); 80 } catch (IOException e) { 81 e.printStackTrace(); 82 } 83 } 84 }); 85 } 86 } 87 88 @Override 89 public void failed(Throwable exc, ByteBuffer attachment) { 90 try { 91 asynchronousSocketChannel.close(); 92 latch.countDown(); 93 } catch (IOException e) { 94 e.printStackTrace(); 95 } 96 } 97 }); 98 } 99 100 @Override 101 public void failed(Throwable exc, AsyncTimeClientHandler attachment) { 102 exc.printStackTrace(); 103 try { 104 asynchronousSocketChannel.close(); 105 latch.countDown(); 106 } catch (IOException e) { 107 e.printStackTrace(); 108 } 109 } 110 }
学到这里我们对NIO编程已经有了一个感性认识。