java 之异步套接字编程实例(AIO)

本文重点以“淘宝邓悟”中学习理解整理而来。更改了客户端为swing应用程序,并增加了服务端与客户端之间相互向对方发信息的功能。为了便 于阅读,用自已观察总结性的理解,进行了啰嗦的注解。 
http://blog.sina.com.cn/s/blog_71ad0d3f01019y1c.html 


   异步socket编程,一样分成客户端与服务端。 
   AsynchronousServerSocketChannel  -------服务端socket; 
   AsynchronousSocketChannel------客户端socket. 
   AsynchronousChannelGroup-----socket管理器。服务端socket与客户端socket都由它生成。它的管理需要线程池。它的工作方式之一是把必要的资源交给客户端与服务端的处理器,并调用该处理器进行工作。 
   ExecutorService-----线程池。是socket管理器需要的东西。 
   CompletionHandler-------处理器。它有两个泛型参数A、V。这是个回调函数所用的标准接口。Socket管理器 会把相关实参放到这个A,V的参数中,让用户处理后,然后调用这个处理器的方法进行执行。如果用户有一个方法中的参数的类型是该处理器,那么在其他地方再次调用这个方法,尽管方法不同,但是传给该方法的CompletionHandler的处理器的A、V参数 却是不相同的,不仅是值不同,类型也有可能完全不同。这是学习中的难点。 

   练习中总结:除了服务端与客户端初始化时差别很大,但是在各自与对方通信中,所使用的类都是 客户端socket类。 

  下面的例子,展示了异步方式的服务端与客户端相互通信的例子。客户端是swing程序。 
   调试使用方法:先运行服务器,再运行客服端。在客户端上的文本框中输入字符点“点我”按钮,立即通过0号套接字向服务器发送信息。在调试台中,可看到服务器与客户端的通信情况。 
下面是我测试时服务端的信息 
引用
debug: 
AioAcceptHandler.completed called 
有客户端连接:/127.0.0.1:1606 
AioAcceptHandler.completed called 
有客户端连接:/127.0.0.1:1607 
收到/127.0.0.1:1606的消息:0 
收到/127.0.0.1:1607的消息:1 
收到/127.0.0.1:1606的消息:sd 
收到/127.0.0.1:1606的消息:1111111111

   
下面是我测试时客户端的信息 
引用

debug: 
收到localhost/127.0.0.1:9008的消息:服务器回应,你输出的是:1 
收到localhost/127.0.0.1:9008的消息:服务器回应,你输出的是:0 
收到localhost/127.0.0.1:9008的消息:服务器回应,你输出的是:sd 
收到localhost/127.0.0.1:9008的消息:服务器回应,你输出的是:1111111111


例子说明: 
  服务端与客户端各有四个类。 
服务端: 
  AioTcpServer---服务器主类。它与客户端通信由回调连接处理器AioAcceptHandler完成。 
  AioAcceptHandler-----连接处理器。处理服务器与客户端的通信。具体的读操作,回调AioReadHandler处理器 
  AioReadHandler-----读处理器。处理连接处理器交给的 读任务。即具体的读客户端的信息由它完成。如果服务器要回应该客户端,需要回调AioWriteHandler写处理器。 
  AioWriteHandler----写处理器。完成读处理器交给的任务,即向客户端回应消息。 

客户端: 
   AioTcpClient-------客户端主类。它与服务器的通讯由回调AioConnectHandler连接处理器完成。具体写信息由客户端socket回调AioSendHandler完成。具体读信息由客户端socket回调AioReadHandler完成。 
   AioConnectHandler-------连接处理器。完成与服务器的通讯。具体的读信息由客户端socket回调读处理器AioReadHandler完成,即完成读取服务器的信息。 
   AioReadHandler-------读处理器,完成读取服务端信息。 
   AioSendHandler----写处理器,向服务端发送信息。 

1.9.3.1 服务端 
AioTcpServer.java 
Java代码   收藏代码
  1. import java.net.InetSocketAddress;   
  2. import java.nio.channels.AsynchronousChannelGroup;   
  3. import java.nio.channels.AsynchronousServerSocketChannel;   
  4. import java.nio.channels.AsynchronousSocketChannel;   
  5. import java.util.concurrent.ExecutorService;   
  6. import java.util.concurrent.Executors;   
  7. import java.util.concurrent.Future;   
  8. /** 
  9.  *     AIO异步socket通讯,分成 用于服务端的socekt与用于客户端的socket,当然这两者都是
     
  10.  * 异步的。两者使用时,都用到了同样的异步通道管理器,异步通道管理器通过线程池管理。
     
  11.  *    异步通道管理器,可以生成服务端socket与客户端socket。 *  
  12.  *    使用服务端socket或客户端socket都需要一个操作处理器(CompletionHandler),
     
  13.  *当有信息时异步通道管理器会把 相关信息传递给操作作处理器。 *  
  14.  *    操作处理器的方法是同一方法,但方法的参数是泛型,随着调用它的方法不同而改变。
     * 
     
  15.  *    在AIO中,CompletionHandler这个操作处理器方法,是个泛型接口,当回调函数用。
     
  16.  * 使用CompletionHandler的方法,约定是把该方法前一个参数实例传递给A型参数
     
  17.  * (attachment),CompletionHandler的另一个参数将是存有该方法的使用情况的实例。 
  18.  *  
  19.  */  
  20. public class AioTcpServer implements Runnable {   
  21.     private AsynchronousChannelGroup asyncChannelGroup;    
  22.     private AsynchronousServerSocketChannel listener;    
  23.     
  24.     public AioTcpServer(int port) throws Exception {   
  25.         //创建线程池  
  26.         ExecutorService executor = Executors.newFixedThreadPool(20);   
  27.         //异步通道管理器  
  28.         asyncChannelGroup = AsynchronousChannelGroup.withThreadPool(executor);   
  29.         //创建 用在服务端的异步Socket.以下简称服务器socket。  
  30.         //异步通道管理器,会把服务端所用到的相关参数  
  31.         listener = AsynchronousServerSocketChannel.open(asyncChannelGroup).  
  32.                 bind(new InetSocketAddress(port));   
  33.     }   
  34.    
  35.     public void run() {   
  36.         try {   
  37.   
  38.             AioAcceptHandler acceptHandler = new AioAcceptHandler();  
  39.             //为服务端socket指定接收操作对象.accept原型是:  
  40.             //accept(A attachment, CompletionHandler  
  41.             // ? super A> handler)  
  42.             //也就是这里的CompletionHandler的A型参数是实际调用accept方法的第一个参数  
  43.             //即是listener。另一个参数V,就是原型中的客户端socket  
  44.             listener.accept(listener, new AioAcceptHandler());    
  45.             Thread.sleep(400000);   
  46.         } catch (Exception e) {   
  47.             e.printStackTrace();   
  48.         } finally {   
  49.             System.out.println("finished server");  
  50.         }   
  51.     }   
  52.    
  53.     public static void main(String... args) throws Exception {   
  54.         AioTcpServer server = new AioTcpServer(9008);   
  55.         new Thread(server).start();   
  56.     }   
  57. }  

   
AioAcceptHandler.java 
Java代码   收藏代码
  1. import client.AioSendHandler;  
  2. import java.io.IOException;   
  3. import java.io.UnsupportedEncodingException;  
  4. import java.nio.ByteBuffer;   
  5. import java.nio.channels.AsynchronousServerSocketChannel;   
  6. import java.nio.channels.AsynchronousSocketChannel;   
  7. import java.nio.channels.CompletionHandler;   
  8. import java.util.concurrent.ExecutionException;   
  9. import java.util.concurrent.Future;   
  10.    
  11. //这里的参数受实际调用它的函数决定。本例是服务端socket.accetp调用决定  
  12. public class AioAcceptHandler implements CompletionHandler  
  13.            
  14. {   
  15.     private  AsynchronousSocketChannel socket;  
  16.     @Override  
  17.     public void completed(AsynchronousSocketChannel socket,   
  18.         AsynchronousServerSocketChannel attachment)   
  19.     { //注意第一个是客户端socket,第二个是服户端socket  
  20.         try {   
  21.             System.out.println("AioAcceptHandler.completed called");  
  22.             attachment.accept(attachment, this);   
  23.             System.out.println("有客户端连接:" +  
  24.                 socket.getRemoteAddress().toString()  
  25.             );   
  26.             startRead(socket);      
  27.         } catch (IOException e) {   
  28.             e.printStackTrace();   
  29.         }   
  30.     }   
  31.    
  32.     @Override  
  33.     public void failed(Throwable exc, AsynchronousServerSocketChannel attachment)   
  34.     {   
  35.         exc.printStackTrace();   
  36.     }   
  37.       
  38.     //不是CompletionHandler的方法  
  39.     public void startRead(AsynchronousSocketChannel socket) {   
  40.         ByteBuffer clientBuffer = ByteBuffer.allocate(1024);   
  41.         //read的原型是  
  42.         //read(ByteBuffer dst, A attachment,  
  43.         //    CompletionHandler handler)   
  44.         //即它的操作处理器,的A型,是实际调用read的第二个参数,即clientBuffer。  
  45.         // V型是存有read的连接情况的参数  
  46.         AioReadHandler rd=new AioReadHandler(socket);  
  47.         socket.read(clientBuffer, clientBuffer, rd);   
  48.         try {               
  49.         } catch (Exception e) {   
  50.             e.printStackTrace();   
  51.         }   
  52.     }   
  53.    
  54. }  


AioReadHandler.java 
Java代码   收藏代码
  1. import java.io.UnsupportedEncodingException;  
  2. import java.nio.ByteBuffer;   
  3. import java.nio.channels.AsynchronousSocketChannel;   
  4. import java.nio.channels.CompletionHandler;   
  5. import java.nio.charset.CharacterCodingException;   
  6. import java.nio.charset.Charset;   
  7. import java.nio.charset.CharsetDecoder;   
  8. import java.util.logging.Level;  
  9. import java.util.logging.Logger;  
  10.   
  11. //这里的参数型号,受调用它的函数决定。这里是受客户端socket.read调用  
  12. public class AioReadHandler implements CompletionHandler  
  13.           
  14. {   
  15.     private AsynchronousSocketChannel socket;   
  16.     public  String msg;  
  17.    
  18.     public AioReadHandler(AsynchronousSocketChannel socket) {   
  19.         this.socket = socket;   
  20.     }       
  21.     private CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();    
  22.       
  23.     @Override  
  24.     public void completed(Integer i, ByteBuffer buf) {   
  25.         if (i > 0) {   
  26.             buf.flip();   
  27.             try {   
  28.                 msg=decoder.decode(buf).toString();  
  29.                 System.out.println("收到" +   
  30.                         socket.getRemoteAddress().toString() + "的消息:" + msg  
  31.                 );   
  32.                 buf.compact();   
  33.             } catch (CharacterCodingException e) {   
  34.                 e.printStackTrace();   
  35.             } catch (IOException e) {   
  36.                 e.printStackTrace();   
  37.             }   
  38.             socket.read(buf, buf, this);   
  39.             try {  
  40.                 write(socket);  
  41.             } catch (UnsupportedEncodingException ex) {  
  42.                 Logger.getLogger(AioReadHandler.class.getName()).log(Level.SEVERE, null, ex);  
  43.             }  
  44.         } else if (i == -1) {   
  45.             try {   
  46.                 System.out.println("客户端断线:" + socket.getRemoteAddress().toString());   
  47.                 buf = null;   
  48.             } catch (IOException e) {   
  49.                 e.printStackTrace();   
  50.             }   
  51.         }   
  52.     }   
  53.   
  54.     @Override  
  55.     public void failed(Throwable exc, ByteBuffer attachment) {  
  56.          System.out.println("cancelled");   
  57.     }  
  58.    
  59.      //不是CompletionHandler的方法  
  60.     public void write(AsynchronousSocketChannel socket) throws UnsupportedEncodingException{  
  61.         String sendString="服务器回应,你输出的是:"+msg;  
  62.         ByteBuffer clientBuffer=ByteBuffer.wrap(sendString.getBytes("UTF-8"));          
  63.         socket.write(clientBuffer, clientBuffer, new AioWriteHandler(socket));  
  64.     }  
  65. }  


AioWriteHandler.java 

Java代码   收藏代码
  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 AioWriteHandler implements CompletionHandler  
  7.       
  8. {   
  9.     private AsynchronousSocketChannel socket;   
  10.    
  11.     public AioWriteHandler(AsynchronousSocketChannel socket) {   
  12.         this.socket = socket;   
  13.     }   
  14.   
  15.     @Override  
  16.     public void completed(Integer i, ByteBuffer buf) {  
  17.         if (i > 0) {   
  18.             socket.write(buf, buf, this);   
  19.         } else if (i == -1) {   
  20.             try {   
  21.                 System.out.println("对端断线:" + socket.getRemoteAddress().toString());   
  22.                 buf = null;   
  23.             } catch (IOException e) {   
  24.                 e.printStackTrace();   
  25.             }   
  26.         }   
  27.           
  28.     }  
  29.   
  30.     @Override  
  31.     public void failed(Throwable exc, ByteBuffer attachment) {  
  32.         System.out.println("cancelled");   
  33.     }  
  34.       
  35. }  


1.9.3.2 客户端 
AioTcpClient.java 

Java代码   收藏代码
  1. import java.awt.BorderLayout;  
  2. import java.awt.FlowLayout;  
  3. import java.awt.event.ActionEvent;  
  4. import java.awt.event.ActionListener;  
  5. import java.io.IOException;  
  6. import java.io.UnsupportedEncodingException;  
  7. import java.net.InetSocketAddress;  
  8. import java.nio.ByteBuffer;  
  9. import java.net.StandardSocketOptions;  
  10. import java.nio.channels.AsynchronousChannelGroup;  
  11. import java.nio.channels.AsynchronousSocketChannel;  
  12. import java.nio.channels.CompletionHandler;  
  13. import java.nio.charset.CharacterCodingException;  
  14. import java.nio.charset.Charset;  
  15. import java.nio.charset.CharsetDecoder;  
  16. import java.util.Timer;  
  17. import java.util.TimerTask;  
  18. import java.util.concurrent.ConcurrentHashMap;  
  19. import java.util.concurrent.ExecutionException;  
  20. import java.util.concurrent.ExecutorService;  
  21. import java.util.concurrent.Executors;  
  22. import java.util.concurrent.Future;  
  23. import java.util.logging.Level;  
  24. import java.util.logging.Logger;  
  25. import javax.swing.JButton;  
  26. import javax.swing.JFrame;  
  27. import javax.swing.JPanel;  
  28. import javax.swing.JTextField;  
  29.   
  30. public class AioTcpClient {  
  31.     public static JTextField jt=new JTextField();  
  32.     public static ConcurrentHashMap  
  33.             sockets =new ConcurrentHashMap<>();  
  34.     static AioTcpClient me;  
  35.       
  36.     private AsynchronousChannelGroup asyncChannelGroup;  
  37.     public AioTcpClient() throws Exception {  
  38.         //创建线程池  
  39.         ExecutorService executor = Executors.newFixedThreadPool(20);  
  40.         //创建异眇通道管理器     
  41.         asyncChannelGroup = AsynchronousChannelGroup.withThreadPool(executor);  
  42.     }  
  43.       
  44.     private final CharsetDecoder decoder = Charset.forName("GBK").newDecoder();  
  45.       
  46.     public void start(final String ip, final int port) throws Exception {  
  47.         // 启动20000个并发连接,使用20个线程的池子  
  48.         for (int i = 0; i < 2; i++) {  
  49.             try {  
  50.                 //客户端socket.当然它是异步方式的。  
  51.                 AsynchronousSocketChannel connector = null;  
  52.                 if (connector == null || !connector.isOpen()) {  
  53.                     //从异步通道管理器处得到客户端socket  
  54.                     connector = AsynchronousSocketChannel.open(asyncChannelGroup);  
  55.                     sockets.putIfAbsent(String.valueOf(i), connector);  
  56.                       
  57.                     connector.setOption(StandardSocketOptions.TCP_NODELAY,  
  58.                         true);  
  59.                     connector.setOption(StandardSocketOptions.SO_REUSEADDR,  
  60.                         true);  
  61.                     connector.setOption(StandardSocketOptions.SO_KEEPALIVE,  
  62.                         true);  
  63.                     //开始连接服务器。这里的的connect原型是  
  64.                     // connect(SocketAddress remote, A attachment,   
  65.                     //  CompletionHandler handler)  
  66.                     // 也就是它的CompletionHandler 的A型参数是由这里的调用方法  
  67.                     //的第二个参数决定。即是connector。客户端连接器。  
  68.                     // V型为null  
  69.                     connector.connect(new InetSocketAddress(ip, port),  
  70.                             connector, new AioConnectHandler(i));  
  71.                 }  
  72.             } catch (IOException e) {  
  73.                 e.printStackTrace();  
  74.             }  
  75.         }  
  76.     }  
  77.       
  78.     public void work() throws Exception{  
  79.         AioTcpClient client = new AioTcpClient();  
  80.         client.start("localhost"9008);  
  81.     }  
  82.   
  83.     public void send() throws UnsupportedEncodingException{  
  84.         AsynchronousSocketChannel socket=sockets.get("0");  
  85.         String sendString=jt.getText();  
  86.         ByteBuffer clientBuffer=ByteBuffer.wrap(sendString.getBytes("UTF-8"));          
  87.         socket.write(clientBuffer, clientBuffer, new AioSendHandler(socket));  
  88.     }  
  89.     public   void createPanel() {  
  90.         me=this;  
  91.         JFrame f = new JFrame("Wallpaper");  
  92.         f.getContentPane().setLayout(new BorderLayout());         
  93.           
  94.         JPanel p=new JPanel(new FlowLayout(FlowLayout.LEFT));          
  95.         JButton bt=new JButton("点我");  
  96.         p.add(bt);  
  97.         me=this;  
  98.         bt.addActionListener(new ActionListener(){  
  99.   
  100.             @Override  
  101.             public void actionPerformed(ActionEvent e) {  
  102.                try {  
  103.                     me.send();  
  104.                    
  105.                 } catch (Exception ex) {  
  106.                     Logger.getLogger(AioTcpClient.class.getName()).log(Level.SEVERE, null, ex);  
  107.                 }  
  108.             }  
  109.           
  110.         });  
  111.           
  112.         bt=new JButton("结束");  
  113.         p.add(bt);  
  114.         me=this;  
  115.         bt.addActionListener(new ActionListener(){  
  116.             @Override  
  117.             public void actionPerformed(ActionEvent e) {                   
  118.             }  
  119.           
  120.         });  
  121.    
  122.         f.getContentPane().add(jt,BorderLayout.CENTER);  
  123.         f.getContentPane().add(p, BorderLayout.EAST);  
  124.           
  125.         f.setSize(450300);  
  126.         f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);  
  127.         f.setLocationRelativeTo (null);  
  128.         f.setVisible (true);  
  129.     }  
  130.         
  131.     public static void main(String[] args) {  
  132.         javax.swing.SwingUtilities.invokeLater(new Runnable() {  
  133.             @Override  
  134.             public void run() {       
  135.                 AioTcpClient d = null;  
  136.                 try {  
  137.                     d = new AioTcpClient();  
  138.                 } catch (Exception ex) {  
  139.                     Logger.getLogger(AioTcpClient.class.getName()).log(Level.SEVERE, null, ex);  
  140.                 }  
  141.                   
  142.                 d.createPanel();  
  143.                 try {  
  144.                     d.work();  
  145.                 } catch (Exception ex) {  
  146.                     Logger.getLogger(AioTcpClient.class.getName()).log(Level.SEVERE, null, ex);  
  147.                 }  
  148.                  
  149.                    
  150.             }  
  151.         });  
  152.     }   
  153. }  


AioConnectHandler.java 
Java代码   收藏代码
  1. import java.util.concurrent.*;  
  2. import java.nio.ByteBuffer;  
  3. import java.nio.channels.AsynchronousSocketChannel;  
  4. import java.nio.channels.CompletionHandler;  
  5.   
  6. public class AioConnectHandler implements CompletionHandler  
  7.       
  8. {  
  9.     private Integer content = 0;  
  10.       
  11.     public AioConnectHandler(Integer value){  
  12.         this.content = value;  
  13.     }  
  14.    
  15.     @Override  
  16.     public void completed(Void attachment,AsynchronousSocketChannel connector) {   
  17.         try {    
  18.          connector.write(ByteBuffer.wrap(String.valueOf(content).getBytes())).get();  
  19.          startRead(connector);   
  20.         } catch (ExecutionException e) {   
  21.             e.printStackTrace();   
  22.         } catch (InterruptedException ep) {   
  23.             ep.printStackTrace();   
  24.         }   
  25.     }   
  26.    
  27.     @Override  
  28.     public void failed(Throwable exc, AsynchronousSocketChannel attachment) {   
  29.         exc.printStackTrace();   
  30.     }   
  31.       
  32.     //这不是 CompletionHandler接口的方法。  
  33.     public void startRead(AsynchronousSocketChannel socket) {   
  34.         ByteBuffer clientBuffer = ByteBuffer.allocate(1024);   
  35.         //read的原型是  
  36.         //read(ByteBuffer dst, A attachment,  
  37.         //    CompletionHandler handler)   
  38.         //即它的操作处理器,的A型,是实际调用read的第二个参数,即clientBuffer。  
  39.         // V型是存有read的连接情况的参数  
  40.         socket.read(clientBuffer, clientBuffer, new AioReadHandler(socket));   
  41.         try {   
  42.               
  43.         } catch (Exception e) {   
  44.             e.printStackTrace();   
  45.         }   
  46.     }  
  47.    
  48. }  


AioReadHandler.java 
Java代码   收藏代码
  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.nio.charset.CharacterCodingException;   
  6. import java.nio.charset.Charset;   
  7. import java.nio.charset.CharsetDecoder;   
  8.    
  9. public class AioReadHandler implements CompletionHandler  
  10.       
  11. {   
  12.     private AsynchronousSocketChannel socket;   
  13.    
  14.     public AioReadHandler(AsynchronousSocketChannel socket) {   
  15.         this.socket = socket;   
  16.     }   
  17.    
  18.     public void cancelled(ByteBuffer attachment) {   
  19.         System.out.println("cancelled");   
  20.     }   
  21.    
  22.     private CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();   
  23.    
  24.     @Override  
  25.     public void completed(Integer i, ByteBuffer buf) {   
  26.         if (i > 0) {   
  27.             buf.flip();   
  28.             try {   
  29.                 System.out.println("收到" + socket.getRemoteAddress().toString() + "的消息:" + decoder.decode(buf));   
  30.                 buf.compact();   
  31.             } catch (CharacterCodingException e) {   
  32.                 e.printStackTrace();   
  33.             } catch (IOException e) {   
  34.                 e.printStackTrace();   
  35.             }   
  36.             socket.read(buf, buf, this);   
  37.         } else if (i == -1) {   
  38.             try {   
  39.                 System.out.println("对端断线:" + socket.getRemoteAddress().toString());   
  40.                 buf = null;   
  41.             } catch (IOException e) {   
  42.                 e.printStackTrace();   
  43.             }   
  44.         }   
  45.     }   
  46.    
  47.     @Override  
  48.     public void failed(Throwable exc, ByteBuffer buf) {   
  49.         System.out.println(exc);   
  50.     }   
  51.   
  52.        
  53. }  


AioSendHandler.java(与服务端的写相同) 
Java代码   收藏代码
  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.nio.charset.CharacterCodingException;  
  6.   
  7.   
  8. public class AioSendHandler implements CompletionHandler  
  9.       
  10. {   
  11.     private AsynchronousSocketChannel socket;   
  12.    
  13.     public AioSendHandler(AsynchronousSocketChannel socket) {   
  14.         this.socket = socket;   
  15.     }   
  16.   
  17.     @Override  
  18.     public void completed(Integer i, ByteBuffer buf) {  
  19.         if (i > 0) {   
  20.             socket.write(buf, buf, this);   
  21.         } else if (i == -1) {   
  22.             try {   
  23.                 System.out.println("对端断线:" + socket.getRemoteAddress().toString());   
  24.                 buf = null;   
  25.             } catch (IOException e) {   
  26.                 e.printStackTrace();   
  27.             }   
  28.         }   
  29.           
  30.     }  
  31.   
  32.     @Override  
  33.     public void failed(Throwable exc, ByteBuffer attachment) {  
  34.         System.out.println("cancelled");   
  35.     }  
  36.       
  37. }  

  • src.rar (8.3 KB)
  • 下载次数: 74

你可能感兴趣的:(base)