本文重点以“淘宝邓悟”中学习理解整理而来。更改了客户端为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 

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


AioAcceptHandler.java 

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


AioReadHandler.java 

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


AioWriteHandler.java 

1. import
2. import
3. import
4. import
5.   
6. public class AioWriteHandler implements
7.     <Integer,ByteBuffer>  
8. {   
9. private
10.    
11. public
12. this.socket = socket;   
13.     }   
14.   
15. @Override
16. public void
17. if (i > 0) {   
18. this);   
19. else if (i == -1) {   
20. try
21. "对端断线:"
22. null;   
23. catch
24.                 e.printStackTrace();   
25.             }   
26.         }   
27.           
28.     }  
29.   
30. @Override
31. public void
32. "cancelled");   
33.     }  
34.       
35. }


1.9.3.2 客户端 


AioTcpClient.java 

1. import
2. import
3. import
4. import
5. import
6. import
7. import
8. import
9. import
10. import
11. import
12. import
13. import
14. import
15. import
16. import
17. import
18. import
19. import
20. import
21. import
22. import
23. import
24. import
25. import
26. import
27. import
28. import
29.   
30. public class
31. public static JTextField jt=new
32. public static
33. new
34. static
35.       
36. private
37. public AioTcpClient() throws
38. //创建线程池
39. 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
47. // 启动20000个并发连接,使用20个线程的池子
48. for (int i = 0; i < 2; i++) {  
49. try
50. //客户端socket.当然它是异步方式的。
51. null;  
52. if (connector == null
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<Void,? super A> handler)
66. // 也就是它的CompletionHandler 的A型参数是由这里的调用方法
67. //的第二个参数决定。即是connector。客户端连接器。
68. // V型为null
69. new
70. new
71.                 }  
72. catch
73.                 e.printStackTrace();  
74.             }  
75.         }  
76.     }  
77.       
78. public void work() throws
79. new
80. "localhost", 9008);  
81.     }  
82.   
83. public void send() throws
84. "0");  
85.         String sendString=jt.getText();  
86. "UTF-8"));          
87. new
88.     }  
89. public   void
90. this;  
91. new JFrame("Wallpaper");  
92. new
93.           
94. new JPanel(new
95. new JButton("点我");  
96.         p.add(bt);  
97. this;  
98. new
99.   
100. @Override
101. public void
102. try
103.                     me.send();  
104.                    
105. catch
106. class.getName()).log(Level.SEVERE, null, ex);  
107.                 }  
108.             }  
109.           
110.         });  
111.           
112. new JButton("结束");  
113.         p.add(bt);  
114. this;  
115. new
116. @Override
117. public void
118.             }  
119.           
120.         });  
121.    
122.         f.getContentPane().add(jt,BorderLayout.CENTER);  
123.         f.getContentPane().add(p, BorderLayout.EAST);  
124.           
125. 450, 300);  
126.         f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);  
127. null);  
128. true);  
129.     }  
130.         
131. public static void
132. new
133. @Override
134. public void
135. null;  
136. try
137. new
138. catch
139. class.getName()).log(Level.SEVERE, null, ex);  
140.                 }  
141.                   
142.                 d.createPanel();  
143. try
144.                     d.work();  
145. catch
146. class.getName()).log(Level.SEVERE, null, ex);  
147.                 }  
148.                  
149.                    
150.             }  
151.         });  
152.     }   
153. }


AioConnectHandler.java 

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


AioReadHandler.java 

AioSendHandler.java(与服务端的写相同) 

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

1. import
2. import
3. import
4. import
5. import
6.   
7.   
8. public class AioSendHandler implements
9.     <Integer,ByteBuffer>  
10. {   
11. private
12.    
13. public
14. this.socket = socket;   
15.     }   
16.   
17. @Override
18. public void
19. if (i > 0) {   
20. this);   
21. else if (i == -1) {   
22. try
23. "对端断线:"
24. null;   
25. catch
26.                 e.printStackTrace();   
27.             }   
28.         }   
29.           
30.     }  
31.   
32. @Override
33. public void
34. "cancelled");   
35.     }  
36.       
37. }