package com.nio.aio.server;
import java.io.IOException;
public class AIOServer {
public static void main(String[] args)throws IOException {
// 設置要監聽的端口
int port = 8788;
if (args != null && args.length > 0){
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
// 創建異步服務器處理類
AIOTimeServerHandler aioServer = new AIOTimeServerHandler(port);
// 啓動線程
new Thread(aioServer, "AIO-Server-Handler").start();
}
}
package com.nio.aio.server;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
public class AcceptComplectionHandler implements CompletionHandler<AsynchronousSocketChannel, AIOTimeServerHandler> {
@Override
public void completed(AsynchronousSocketChannel result, AIOTimeServerHandler attachment) {
/**
* 爲什麼要再次調用accept方法呢?
* 原因: 調用該方法以後,如果有新的客戶端連接接入,系統將回調我們傳入的
*/
attachment.asynchronousServerSocketChannel.accept(attachment, this);
// 創建ByteBuffer對象,預分配1MB的緩衝區
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 進行異步讀的操作
/**
* 參數的分析:
* 1 接收緩衝區用於從異步channel中讀取數據包
* 2 異步channel攜帶的附件,通知回調的時候作爲參數使用
* 3 接收通知回調的業務handler
*/
result.read(buffer,buffer,new ReadComplectionHandler(result));
}
@Override
public void failed(Throwable exc, AIOTimeServerHandler attachment) {
exc.printStackTrace();
attachment.latch.countDown();
}
}
package com.nio.aio.server;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.util.concurrent.CountDownLatch;
public class AIOTimeServerHandler implements Runnable {
private int port;
CountDownLatch latch;
AsynchronousServerSocketChannel asynchronousServerSocketChannel;
public AIOTimeServerHandler(int port) {
this.port = port;
try {
// 創建異步服務通道
asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open();
// 綁定監聽端口號
asynchronousServerSocketChannel.bind(new InetSocketAddress(port));
System.out.println("服務端啓動成功,端口號是:" + port);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
// 初始化CountDownLatch對象,作用:在完成一組正在執行的操作之前,允許當前的線程一直阻塞。
// 這個例子在這阻塞是防止服務端執行完成退出。
latch = new CountDownLatch(1);
// 用於接收客戶端的連接,異步操作
doAccept();
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void doAccept() {
asynchronousServerSocketChannel.accept(this, new AcceptComplectionHandler());
}
}
package com.nio.aio.server;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.Date;
public class ReadComplectionHandler implements CompletionHandler<Integer, ByteBuffer> {
private AsynchronousSocketChannel channel;
public ReadComplectionHandler(AsynchronousSocketChannel channel) {
if (this.channel == null){
this.channel = channel;
}
}
@Override
public void completed(Integer result, ByteBuffer attachment) {
// 進行flip操作,爲後續從緩衝區讀取數據做準備
attachment.flip();
// 根據緩衝區可讀的字節數創建字節數組
byte[] body = new byte[attachment.remaining()];
// 將緩衝區的可讀的字節數組複製到新創建的字節數組中
attachment.get(body);
try {
// 編碼
String req = new String(body, "utf-8");
// 打印服務端收到的客戶端傳來的消息
System.out.println("服務端收到的消息是:" + req);
// 如果收到的消息和服務端預設值的消息相同就返回給客戶端當前時間
String currentTime = "AIO TIME TEST".equalsIgnoreCase(req) ? new Date(System.currentTimeMillis()).toString() : "客戶端發送的消息不是AIO TIME TEST";
doWrite(currentTime);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
private void doWrite(String currentTime) {
// 非空和去除空格,校驗
if (currentTime != null && currentTime.trim().length() > 0){
// 使用默認的編碼方式對currentTime編碼,將編碼以後的結果放到byte數組
byte[] bytes = currentTime.getBytes();
// 分配一個新的字節緩衝區,根據上面的字節數組
ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
// 將字節數組中的數據複製到緩衝區中
writeBuffer.put(bytes);
// 進行flip操作,爲後續從緩衝區讀取數據做準備
writeBuffer.flip();
/**
* 該方法發起一個異步寫操作,從給定的緩衝區向該通道寫入字節序列
* 參數的分析:
* 1 要檢索字節的緩衝區
* 2 連接到I/O操作的對象
* 3 接收通知回調的業務handler
*/
channel.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
// 如果沒有發送完成,繼續發送
if (attachment.hasRemaining()){
channel.write(attachment, attachment, this);
}
}
/**
* 當發生異常的時候,對隱藏進行判斷,如果是IO異常,關閉鏈路釋放資源
* @param exc
* @param attachment
*/
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
try {
this.channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
【1】AIO入門案例客戶端的代碼具體實現以及詳細註釋
https://blog.csdn.net/wildwolf_001/article/details/81103006
【2】NIO入門案例使用netty最新版本框架代碼實現及詳細註釋
https://blog.csdn.net/wildwolf_001/article/details/81132896
【3】NIO入門案例客戶端的代碼具體實現以及詳細註釋
https://blog.csdn.net/wildwolf_001/article/details/81102953
【4】NIO入門案例之分析NIO服務端序列圖
https://blog.csdn.net/wildwolf_001/article/details/81069180