AIO(Asynchronous IO)即異步IO,特別需要說明的是,Java AIO需要JDK 1.7的支持
客戶端
package com.test.client;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.log4j.Logger;
import com.test.handler.client.ConnectCompleteHandler;
public class Client {
private Logger logger = Logger.getLogger(Client.class);
private String host = "127.0.0.1";
private int port = 9999;
private int poolSize = 10;
private static CountDownLatch serverStatus = new CountDownLatch(1);
public Client() throws Exception {
try {
//池中的每個線程都在等待IO事件,當IO操作完成後,調用池中的線程處理CompleteHandler
ExecutorService threadPool = Executors.newFixedThreadPool(poolSize);
AsynchronousChannelGroup asyncChannelGroup
= AsynchronousChannelGroup.withThreadPool(threadPool);
AsynchronousSocketChannel asyncSocketChannel =
AsynchronousSocketChannel.open(asyncChannelGroup);
asyncSocketChannel.setOption(StandardSocketOptions.TCP_NODELAY, true);
asyncSocketChannel.connect(new InetSocketAddress(host, port),
null, new ConnectCompleteHandler(asyncSocketChannel));
} catch (IOException e) {
logger.error("Cilent socket establish failed!");
throw e;
}
}
public static void main(String[] args) throws Exception {
Client client = new Client();
serverStatus.await();
}
}
客戶端處理器
package com.test.handler.client;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import org.apache.log4j.Logger;
//CompletionHandler<V,A>
//V-IO操作的結果,AsynchronousSocketChannel.open創建的異步連接,
// asyncSocketChannel.connect實際沒有IO操作,因此IO操作的結果爲Void
//A-IO操作附件,
public class ConnectCompleteHandler
implements CompletionHandler<Void, Object> {
private Logger logger = Logger.getLogger(ConnectCompleteHandler.class);
AsynchronousSocketChannel asyncSocketChannel;
public ConnectCompleteHandler(
AsynchronousSocketChannel asyncSocketChannel){
this.asyncSocketChannel = asyncSocketChannel;
}
@Override
public void completed(Void result, Object attachment) {
//使用asyncChannelGroup中保存的線程池中的線程進行處理
logger.info("Deal thread of [ConnectCompleteHandler] : "
+ Thread.currentThread().getName());
String request = "Hi, this is client!";
logger.info("The request sent by client is : " + request);
try {
byte[] reqBytes = request.getBytes("utf-8");
ByteBuffer writeByteBuffer = ByteBuffer.allocate(reqBytes.length);
writeByteBuffer.put(reqBytes);
writeByteBuffer.flip();
asyncSocketChannel.write(writeByteBuffer, asyncSocketChannel,
new WriteCompleteHandler());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, Object attachment) {
logger.error("Connection error!");
}
}
package com.test.handler.client;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import org.apache.log4j.Logger;
//CompletionHandler<V,A>
//V-IO操作的結果,這裏是write操作寫成功的字節數
//A-IO操作附件,這裏傳入AsynchronousSocketChannel便於獲得服務端響應
public class WriteCompleteHandler
implements CompletionHandler<Integer, AsynchronousSocketChannel> {
private Logger logger = Logger.getLogger(WriteCompleteHandler.class);
@Override
public void completed(Integer result,
AsynchronousSocketChannel asyncSocketChannel) {
logger.info("Deal thread of [WriteCompleteHandler] : "
+ Thread.currentThread().getName());
logger.info("Write bytes : " + result.intValue());
if(result.intValue() == -1){
logger.error("Send request to server error!");
}else{
ByteBuffer readByteBuffer = ByteBuffer.allocate(100);
//獲取服務端發送的響應
asyncSocketChannel.read(readByteBuffer, readByteBuffer,
new ReadCompleteHandler());
}
}
@Override
public void failed(Throwable exc,
AsynchronousSocketChannel asyncSocketChannel) {
logger.error("Write message error!");
exc.printStackTrace();
}
}
package com.test.handler.client;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.CompletionHandler;
import org.apache.log4j.Logger;
//CompletionHandler<V,A>
//V-IO操作的結果,這裏是read操作成功讀取的字節數
//A-IO操作附件,由於WriteCompleteHandler中調用asyncSocketChannel.read方法時
// 傳入了ByteBuffer,所以這裏是ByteBuffer
public class ReadCompleteHandler
implements CompletionHandler<Integer, ByteBuffer> {
private Logger logger = Logger.getLogger(ReadCompleteHandler.class);
@Override
public void completed(Integer result, ByteBuffer respByteBuffer) {
logger.info("Deal thread of [ReadCompleteHandler] : "
+ Thread.currentThread().getName());
logger.info("Read bytes : " + result.intValue());
if(result.intValue() == -1){
logger.error("Get response from server error!");
}else{
respByteBuffer.flip();
byte[] respBytes = new byte[respByteBuffer.remaining()];
respByteBuffer.get(respBytes);
try {
String response = new String(respBytes, "utf-8");
logger.info("The response sent by server is : " + response);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
@Override
public void failed(Throwable exc, ByteBuffer readByteBuffer) {
logger.error("Read message error!");
exc.printStackTrace();
}
}
服務端
package com.test.server;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.log4j.Logger;
import com.test.handler.server.ConnectCompleteHandler;
public class Server {
private Logger logger = Logger.getLogger(Server.class);
private String host = "127.0.0.1";
private int port = 9999;
private int poolSize = 10;
private static CountDownLatch serverStatus = new CountDownLatch(1);
private AsynchronousServerSocketChannel asyncServerSocketChannel;
public Server() throws Exception {
try{
//池中的每個線程都在等待IO事件,當IO操作完成後,觸發相應的IO時間,調用池中的線程IO回調函數(CompleteHandler)
ExecutorService threadPool = Executors.newFixedThreadPool(poolSize);
AsynchronousChannelGroup asyncChannelGroup
= AsynchronousChannelGroup.withThreadPool(threadPool);
asyncServerSocketChannel = AsynchronousServerSocketChannel.open(asyncChannelGroup);
asyncServerSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
asyncServerSocketChannel.bind(new InetSocketAddress(host, port));
logger.info("Server start up!");
}catch(Exception e){
logger.error("Server establish error!");
throw e;
}
}
public void service(){
// 這種寫法將拋出java.nio.channels.AcceptPendingException異常
// 只有一個連接建立成功之後,才能再建立下一個連接
// while(true){
// asyncServerSocketChannel.accept();
// }
// AIO支持直接返回Future對象,但其實此刻調用並未完成,
// while(true){
// try {
// Future<AsynchronousSocketChannel> acceptFuture = asyncServerSocketChannel.accept();
//// wait直到調用完成
// AsynchronousSocketChannel asyncSocketChannel = acceptFuture.get();
// logger.info("Connection complete!");
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// 由於asyncChannelGroup的存在,回調是更好的實現方式
asyncServerSocketChannel.accept(asyncServerSocketChannel, new ConnectCompleteHandler());
}
public static void main(String[] args) throws Exception {
Server server = new Server();
server.service();
//由於AIO的方法都是直接返回的,這裏必須使用鎖以避免線程退出,服務停止
//所謂AIO,既發起請求之後,當前線程可以去幹別的事,當請求完成後會得到通知
//作爲一個全職服務端,main線程其實也沒什麼別的事情可幹,也許還是客戶端更加適合使用AIO
serverStatus.await();
}
}
服務端處理器
package com.test.handler.server;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import org.apache.log4j.Logger;
// CompletionHandler<V,A>
// V-IO操作的結果,這裏是成功建立的連接,AsynchronousSocketChannel
// A-IO操作附件,這裏傳入AsynchronousServerSocketChannel便於繼續接收請求建立新連接
public class ConnectCompleteHandler
implements CompletionHandler<AsynchronousSocketChannel,
AsynchronousServerSocketChannel> {
private Logger logger = Logger.getLogger(ConnectCompleteHandler.class);
@Override
public void completed(AsynchronousSocketChannel asyncSocketChannel,
AsynchronousServerSocketChannel asyncServerSocketChannel) {
//使用asyncChannelGroup中保存的線程池中的線程進行處理
logger.info("Deal thread of [ConnectCompleteHandler] : "
+ Thread.currentThread().getName());
//當前連接建立成功後,接收下一個請求建立新的連接
asyncServerSocketChannel.accept(asyncServerSocketChannel,
new ConnectCompleteHandler());
//ByteBuffer是非線程安全的,如果要在多個線程間共享同一個ByteBuffer,需要考慮線程安全性問題
ByteBuffer readByteBuffer = ByteBuffer.allocate(100);
//獲取客戶端發送的請求
asyncSocketChannel.read(readByteBuffer, readByteBuffer,
new ReadCompleteHandler(asyncSocketChannel));
}
@Override
public void failed(Throwable exc, AsynchronousServerSocketChannel attachment) {
logger.error("Connection error!");
}
}
package com.test.handler.server;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import org.apache.log4j.Logger;
//CompletionHandler<V,A>
//V-IO操作的結果,這裏是read操作成功讀取的字節數
//A-IO操作附件,由於ConnectCompleteHandler中調用asyncSocketChannel.read方法時
// 傳入了ByteBuffer,所以這裏爲ByteBuffer
public class ReadCompleteHandler
implements CompletionHandler<Integer, ByteBuffer> {
private Logger logger = Logger.getLogger(ReadCompleteHandler.class);
private AsynchronousSocketChannel asyncSocketChannel;
public ReadCompleteHandler(AsynchronousSocketChannel asyncSocketChannel){
this.asyncSocketChannel = asyncSocketChannel;
}
@Override
public void completed(Integer result, ByteBuffer readByteBuffer) {
logger.info("Deal thread of [ReadCompleteHandler] : "
+ Thread.currentThread().getName());
logger.info("Read bytes : " + result.intValue());
if(result.intValue() == -1){
logger.error("Get request from client error!");
}else{
readByteBuffer.flip();
byte[] reqBytes = new byte[readByteBuffer.remaining()];
readByteBuffer.get(reqBytes);
try {
String request = new String(reqBytes, "utf-8");
logger.info("The request sent by client is : " + request);
String response = "Hi, this is server!";
logger.info("The response has been sent back to client is : "
+ response);
byte[] respBytes = response.getBytes("utf-8");
ByteBuffer writeByteBuffer = ByteBuffer.allocate(respBytes.length);
writeByteBuffer.put(respBytes);
writeByteBuffer.flip();
// asyncSocketChannel.write(writeByteBuffer);
asyncSocketChannel.write(writeByteBuffer, null, new WriteCompleteHandler());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
@Override
public void failed(Throwable exc, ByteBuffer readByteBuffer) {
logger.error("Read message error!");
exc.printStackTrace();
}
}
package com.test.handler.server;
import java.nio.channels.CompletionHandler;
import org.apache.log4j.Logger;
//CompletionHandler<V,A>
//V-IO操作的結果,這裏是write操作寫成功的字節數
//A-IO操作附件,
public class WriteCompleteHandler
implements CompletionHandler<Integer, Object> {
private Logger logger = Logger.getLogger(WriteCompleteHandler.class);
@Override
public void completed(Integer result, Object attachment) {
logger.info("Deal thread of [WriteCompleteHandler] : "
+ Thread.currentThread().getName());
logger.info("Write bytes : " + result.intValue());
if(result.intValue() == -1)
logger.info("Send response to client error!" );
else
logger.info("The response has been sent back to client successfully!" );
}
@Override
public void failed(Throwable exc, Object attachment) {
logger.error("Write message error!");
exc.printStackTrace();
}
}
log4j日誌配置文件
log4j.rootLogger=info,logOutput
#log console out put
log4j.appender.logOutput=org.apache.log4j.ConsoleAppender
log4j.appender.logOutput.layout=org.apache.log4j.PatternLayout
log4j.appender.logOutput.layout.ConversionPattern=%p%d{[yy-MM-dd HH:mm:ss]}[%c] -> %m%n
Server端運行結果
INFO[16-08-04 01:20:22][com.test.server.Server] -> Server start up!
INFO[16-08-04 01:20:26][com.test.handler.server.ConnectCompleteHandler] -> Deal thread of [ConnectCompleteHandler] : pool-1-thread-1
INFO[16-08-04 01:20:26][com.test.handler.server.ReadCompleteHandler] -> Deal thread of [ReadCompleteHandler] : pool-1-thread-2
INFO[16-08-04 01:20:26][com.test.handler.server.ReadCompleteHandler] -> Read bytes : 19
INFO[16-08-04 01:20:26][com.test.handler.server.ReadCompleteHandler] -> The request sent by client is : Hi, this is client!
INFO[16-08-04 01:20:26][com.test.handler.server.ReadCompleteHandler] -> The response has been sent back to client is : Hi, this is server!
INFO[16-08-04 01:20:26][com.test.handler.server.WriteCompleteHandler] -> Deal thread of [WriteCompleteHandler] : pool-1-thread-3
INFO[16-08-04 01:20:26][com.test.handler.server.WriteCompleteHandler] -> Write bytes : 19
INFO[16-08-04 01:20:26][com.test.handler.server.WriteCompleteHandler] -> The response has been sent back to client successfully!
Client端運行結果
INFO[16-08-04 01:20:26][com.test.handler.client.ConnectCompleteHandler] -> Deal thread of [ConnectCompleteHandler] : pool-1-thread-1
INFO[16-08-04 01:20:26][com.test.handler.client.ConnectCompleteHandler] -> The request sent by client is : Hi, this is client!
INFO[16-08-04 01:20:26][com.test.handler.client.WriteCompleteHandler] -> Deal thread of [WriteCompleteHandler] : pool-1-thread-2
INFO[16-08-04 01:20:26][com.test.handler.client.WriteCompleteHandler] -> Write bytes : 19
INFO[16-08-04 01:20:26][com.test.handler.client.ReadCompleteHandler] -> Deal thread of [ReadCompleteHandler] : pool-1-thread-3
INFO[16-08-04 01:20:26][com.test.handler.client.ReadCompleteHandler] -> Read bytes : 19
INFO[16-08-04 01:20:26][com.test.handler.client.ReadCompleteHandler] -> The response sent by server is : Hi, this is server!