阻塞I/O
當read沒有數據時,將阻塞一直等待有數據爲止,同時需要爲每一個socket創建一個線程,耗費資源。
多路複用
現在只要搜NIO相關的知識,都會告訴你使用了IO多路複用技術?那麼什麼是IO多路複用?多路是什麼多路?複用又是複用了什麼內容?
多路:多個Socket連接,即是NIO網絡編程中的多個channel。
複用:複用是指複用一個線程對多路Socket連接的狀態進行監控,實現對多個I/O流的管理能力。
1、NIO被稱爲非阻塞式IO就是selector的緣故,在阻塞IO中會一直等待read有數據到來,而在NIO中根據事件來開始流的讀寫,無須一直等待。更牛的是NIO一樣可以使用阻塞模式,通過configureBlocking進行配置。
2、NIO的核心就是事件註冊和事件輪詢,通過Selector實現。
反應器模式
看完圖是不是有點迷惑這個不是與觀察者一樣嗎? 當事件發生改變,就通知所有需要知道事件的人。其實反應器模式和觀察者模式最大的不同在於一個是單事件源(觀察者模式),一個是多事件源(反應器模式)。
實戰
程序一:NIO服務端代碼
public class MyServer {
Selector selector;
ServerSocketChannel serverSocketChannel;
ByteBuffer bb = ByteBuffer.allocate(200);
public static void main(String[] args) throws IOException {
new MyServer().init();
}
public void init() throws IOException {
/// 第一步:打開selector
selector = Selector.open();
/// 第二步:打開serverSocketChannel通道,並設置爲非阻塞模式
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(8888));
serverSocketChannel.configureBlocking(false);
/// 第三步: 將serverSocketChannel註冊爲可以隨時接受連接
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
handler();
}
public void handler() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
// 阻塞模式 ,等待新的事件發生
selector.select();
Iterator<SelectionKey> itor = selector.selectedKeys().iterator();
while (itor.hasNext()) {
SelectionKey sk = itor.next();
itor.remove(); // 防止重複處理註冊的事件
// 已經準備好接受連接 - 肯定是針對服務端纔有
if (sk.isAcceptable()) {
ServerSocketChannel ss = (ServerSocketChannel) sk.channel();
SocketChannel ssc = ss.accept();// 獲取一個連接上來的socketChannel
ssc.configureBlocking(false); // 設置通道不爲阻塞模式
ssc.register(selector, SelectionKey.OP_READ);
} else
// 準備好讀取數據
if (sk.isReadable()) {
SocketChannel ss = null;
try {
ss = (SocketChannel) sk.channel();
int i = ss.read(bb);
if(i != -1) {
bb.flip();
System.out.println(new String(bb.array(), 0, bb.limit()));
System.out.println("數據讀入完成");
bb.clear();
}else {
ss.close();
}
} catch (Exception e) {
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
}