AIO创建的TimeServer源码分析

《Netty权威指南》第2章NIO入门,本章中,我们会分别对JDK的BIO、NIO和JDK1.7最新提供的NIO2.0的使用进行详细说明,通过流程图和代码讲解,让大家体会到随着Java I/O类库的不断发展和改进,基于Java的网络编程会变得越来越简单,随着异步I/O功能的增强,基于Java NIO开发的网络服务器甚至不逊色于采用C++开发的网络程序。本节为大家介绍AIO创建的TimeServer源码分析。

作者:李林锋来源:电子工业出版社|2014-07-09 11:57

 收藏

  分享

9月15日技术沙龙 | 如何将智能化和运维工作相结合,实现智能运维!

2.4.1  AIO创建的TimeServer源码分析(1)

首先看下时间服务器的主函数。

代码清单2-11  AIO时间服务器服务端  TimeClientHandle

 
  1. 10. public class TimeServer {  
  2. 11.   
  3. 12.     /**  
  4. 13.      * @param args  
  5. 14.      * @throws IOException  
  6. 15.      */  
  7. 16.     public static void main(String[] args) throws IOException {  
  8. 17.     int port = 8080;  
  9. 18.     if (args != null && args.length > 0) {  
  10. 19.         try {  
  11. 20.         port = Integer.valueOf(args[0]);  
  12. 21.         } catch (NumberFormatException e) {  
  13. 22.         // 采用默认值  
  14. 23.         }  
  15. 24.     }  
  16. 25.     AsyncTimeServerHandler timeServer=new AsyncTimeServerHandler(port);  
  17. 26.     new Thread(timeServer, "AIO-AsyncTimeServerHandler-001").start();  
  18. 27.     }  
  19. 28. } 

我们直接从第25行开始看,首先创建异步的时间服务器处理类,然后启动线程将AsyncTimeServerHandler拉起,代码如下。

代码清单2-12  AIO时间服务器服务端 

 
  1. 13. public class AsyncTimeServerHandler implements Runnable {  
  2. 14.   
  3. 15.     private int port;  
  4. 16.   
  5. 17.     CountDownLatch latch;  
  6. 18.     AsynchronousServerSocketChannel asynchronousServerSocketChannel;  
  7. 19.   
  8. 20.     public AsyncTimeServerHandler(int port) {  
  9. 21.     this.port = port;  
  10. 22.     try {  
  11. 23.         asynchronousServerSocketChannel = AsynchronousServerSocketChannel 
  12. 24.             .open();  
  13. 25.         asynchronousServerSocketChannel.bind(new InetSocketAddress(port));  
  14. 26.         System.out.println("The time server is start in port : " + port);  
  15. 27.     } catch (IOException e) {  
  16. 28.         e.printStackTrace();  
  17. 29.     }  
  18. 30.     }  
  19. 31.   
  20. 32.     /*  
  21. 33.      * (non-Javadoc)  
  22. 34.      *   
  23. 35.      * @see java.lang.Runnable#run()  
  24. 36.      */  
  25. 37.     @Override  
  26. 38.     public void run() {  
  27. 39.   
  28. 40.     latch = new CountDownLatch(1);  
  29. 41.     doAccept();  
  30. 42.     try {  
  31. 43.         latch.await();  
  32. 44.     } catch (InterruptedException e) {  
  33. 45.         e.printStackTrace();  
  34. 46.     }  
  35. 47.     }  
  36. 48.   
  37. 49.     public void doAccept() {  
  38. 50.     asynchronousServerSocketChannel.accept(this,  
  39. 51.         new AcceptCompletionHandler());  
  40. 52.     } 

我们重点对AsyncTimeServerHandler进行分析。首先看20~27行,在构造方法中,我们首先创建一个异步的服务端通道AsynchronousServerSocketChannel,然后调用它的bind方法绑定监听端口,如果端口合法且没被占用,绑定成功,打印启动成功提示到控制台。

在线程的run方法中,第40行我们初始化CountDownLatch对象,它的作用是在完成一组正在执行的操作之前,允许当前的线程一直阻塞。在本例程中,我们让线程在此阻塞,防止服务端执行完成退出。在实际项目应用中,不需要启动独立的线程来处理AsynchronousServerSocketChannel,这里仅仅是个demo演示。

第41行用于接收客户端的连接,由于是异步操作,我们可以传递一个CompletionHandler <AsynchronousSocketChannel,? super A>类型的handler实例接收accept操作成功的通知消息,在本例程中我们通过AcceptCompletionHandler实例作为handler来接收通知消息,下面继续对AcceptCompletionHandler进行分析。

代码清单2-13  AIO时间服务器服务端  AcceptCompletionHandler

 
  1. 14.   
  2. 15.     @Override  
  3. 16.     public void completed(AsynchronousSocketChannel result,  
  4. 17.         AsyncTimeServerHandler attachment) {  
  5. 18.     attachment.asynchronousServerSocketChannel.accept(attachment, this);  
  6. 19.     ByteBuffer buffer = ByteBuffer.allocate(1024);  
  7. 20.     result.read(buffer, buffer, new ReadCompletionHandler(result));  
  8. 21.     }  
  9. 22.   
  10. 23.     @Override  
  11. 24.     public void failed(Throwable exc,AsyncTimeServerHandler attachment) {  
  12. 25.     exc.printStackTrace();  
  13. 26.     attachment.latch.countDown();  
  14. 27.     }  
  15. 28. } 

CompletionHandler有两个方法,分别如下。

public void completed(AsynchronousSocketChannel result, AsyncTimeServerHandler attachment);

public void failed(Throwable exc, AsyncTimeServerHandler attachment)。

下面我们分别对这两个接口的实现进行分析。首先看completed接口的实现,代码18~20行,我们从attachment获取成员变量AsynchronousServerSocketChannel,然后继续调用它的accept方法。有的读者在此可能会心存疑惑:既然已经接收客户端成功了,为什么还要再次调用accept方法呢?原因是这样的:当我们调用AsynchronousServerSocketChannel的accept方法后,如果有新的客户端连接接入,系统将回调我们传入的CompletionHandler实例的completed方法,表示新的客户端已经接入成功,因为一个AsynchronousServerSocket Channel可以接收成千上万个客户端,所以我们需要继续调用它的accept方法,接收其他的客户端连接,最终形成一个循环。每当接收一个客户读连接成功之后,再异步接收新的客户端连接

转载于:https://my.oschina.net/zpf2016/blog/1938883

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值