#JAVA NIO
JAVA NIO的定義
IO大家都知道是Input 與Output的縮寫,而N是New的意思,java 1.4在不替換原有的IO實現的情況下,新增加一套IO機制,所以叫NIO,然後舊的叫OIO。
爲什麼學習Java NIO?
因爲高性能的通訊框架底層很多都用到了它,如果不學習它,導致在看那些框架的源碼看不懂,比如Netty,tomcat 7+等
它出現的目的
因爲java爲了實現write once run anywhere做出個JVM,通過Jvm屏蔽操作系統之間差異,帶來的好處很明顯,劣勢就是屏蔽太多系統之間的特點,比如一些操作系統所對IO的優勢,所以javaNIO就是解決OIO所存在的IO問題的,比如OIO會存在的就數據讀取是網卡讀取內核的空間,再拷貝到用戶空間,在NIO裏有直接支持零拷貝技術,所以Netty就是利用這一點實現壓榨服務器資源。
如下根據java NIO 實現聊天室的Server端代碼
public class ServerSocketWithNIO {
private List<SocketChannel> socketChannels = new ArrayList<>();
public static void main(String[] args) throws IOException {
new ServerSocketWithNIO().go(args);
}
public void go(String[] args) throws IOException {
//創建serverSocketChannel
ServerSocketChannel serverSocketChannel = = SelectorProvider.provider().open();
//綁定端口
ServerSocket serverSocket = serverSocketChannel.socket();
serverSocketChannel.configureBlocking(false);
serverSocket.bind(new InetSocketAddress(Integer.parseInt(args[0])));
//創建Selector
Selector selector = Selector.open();
//註冊感興趣事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
//獲取就緒事件個數
int select = selector.select();
if (select > 0) {
//獲取IO已就緒的selectedKeys
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
//新連接進來,註冊讀事件
if (selectionKey.isAcceptable()) {
ServerSocketChannel channel = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = channel.accept();
socketChannel.configureBlocking(false);
socketChannels.add(socketChannel);
socketChannel.register(selector, SelectionKey.OP_READ);
sayHello(socketChannel);
}
//讀取數據
if (selectionKey.isReadable()) {
readDataFromChannel((SocketChannel) selectionKey.channel());
}
//處理完之前要從集合裏刪除
iterator.remove();
}
}
}
}
private void readDataFromChannel(SocketChannel channel) throws IOException {
ByteBuffer allocate = ByteBuffer.allocate(1024);
while (channel.read(allocate) > 0) {
allocate.flip();
while (allocate.hasRemaining()) {
//向所有的發送消息
socketChannels.forEach(socketChannel -> {
if (socketChannel != channel) {
try {
socketChannel.write(allocate);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
allocate.clear();
}
}
private void sayHello(SocketChannel socketChannel) throws IOException {
socketChannel.write(UTF_8.encode("歡迎來到嘿嘿聊天室!!!"));
}
}
其中表涉及到四個概念buffer,channel,seletor,selectKey
其中 channel理解成一個連接通道,可能基於這個通道進行一系列的IO操作,如socket上的操作accept, read, write等
然後buffer可以理解成一個緩衝區,在channel讀取到的字節可以放到buffer裏存放然後讀取等;
selector可以根據字面的意思理解成一個選擇器,就是根據註冊到上面的channel列表選擇出可進行IO操作的Channel;
selectKey可以理解channel與selector之間的註冊關係
所以它的主要流程
- 創建channel
- 綁定端口
- 創建selector
- 把channel根據感興趣的事件註冊到selector
- 循環獲取selector返回IO就緒的channel列表,然後做相應的業務處理
其中這四個概念詳細學習可以下載java NIO,看完它會對java NIO有個整體的瞭解