Netty - 眼熟NIO
Netty系列文章 - 眼熟Nio
什麼是IO?什麼是NIO?
- IO:
- java.io中最為核心的概念是流(
stream
),面向流程式設計,java中,一個流要麼是輸入流,要麼是輸出流
- java.io中最為核心的概念是流(
- NIO:
- java.nio中擁有3個核心概念:
selector
.channel
.buffer
; java.nio中,面向塊(block)或是緩衝區(buffer)程式設計的, - java中的原生8種基本資料型別都有各自對應的buffer型別,(除Boolean外),如
IntBuffer
,CharBuffer
,ByteBuffer
,LongBuffer
,ShortBuffer
- 所有資料的讀寫都是通過
buffer
來進行的,永遠不會出現直接channel
中直接寫入,讀取資料 - 與
stream
不同的是,channel
是雙向的,一個流只可能是InputStream
或是OutputStream
,channel
則是雙向的,channel
開啟後可以進行讀又可以進行寫
- java.nio中擁有3個核心概念:
3個核心概念
Buffer
Buffer屬性以及相關操作.
屬性 | 說明 |
---|---|
capacity 最大容量 | 它永遠不可能為負數,並且是不會變化的 |
position 位置 | 下一個讀或寫的位置,它永遠不可能為負數,並且不會大於limit |
limit 限制 | 它永遠不可能為負數,並且不會大於capacity |
mark 標記 | 標記位置,用於記錄某次讀寫的位置,可以通過reset()方法回到這裡 |
public class Dome1 {
public static void main(String[] args) {
// 分配一塊容量大小為8個長度的Buffer塊
IntBuffer buffer = IntBuffer.allocate(5);
// 生成隨機數存入buffer中
for (int i = 0; i < buffer.capacity(); i++) {
int nextInt = new Random().nextInt(20);
buffer.put(nextInt);
}
/**
*
* 反轉一下
* 其實核心也就是執行了這兩行程式碼
* limit = position;
* position = 0;
*/
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print(buffer.get()+"\t"); //輸出結果: 3 1 4 5 10
}
}
}
Buffer初始化完成後圖示
每put或get
一次資料``position`就會往右移動一次
呼叫buffer.flip();
後limit = position; position = 0;
Channel
常見的Channel實現有
FileChannel:檔案讀寫資料通道
SocketChannel:TCP讀寫網路資料通道
ServerSocketChannel:服務端網路資料讀寫通道,可以監聽TCP連線。對每一個新進來的連線都會建立一個SocketChannel: 客戶端網路資料讀寫通道.
DatagramChannel:UDP讀寫網路資料通道
通道表示開啟到 IO 裝置(例如:檔案、套接字)的連線。若需要使用 NIO 系統,需要獲取用於連線 IO 裝置的通道以及用於容納資料的緩衝區。然後操作緩衝區,對資料進行處理。
Channel相比IO中的Stream更加高效,可以非同步雙向傳輸,但是必須和buffer一起使用。
// 讀一個檔案內容
public class Dome2 {
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream("dome2.txt");
FileChannel channel = fileInputStream.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
channel.read(byteBuffer);
byteBuffer.flip();
while (byteBuffer.remaining() > 0) {
System.err.println((char) byteBuffer.get());
}
fileInputStream.close();
}
}
輸出結果
H
e
l
l
o
// 從一個檔案讀資料並寫到另一個檔案內!
public class Dome4 {
public static void main(String[] args) throws Exception {
FileOutputStream fileOutputStream = new FileOutputStream("dome4write.txt");
FileInputStream fileInputStream = new FileInputStream("dome4read.txt");
FileChannel channelRead = fileInputStream.getChannel();
FileChannel channelWrite = fileOutputStream.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(100);
while (true) {
// 注意這個clear方法
byteBuffer.clear();
System.out.println(byteBuffer.position());
int readNumber = channelRead.read(byteBuffer);
System.out.println(readNumber);
if (-1 == readNumber) {
break;
}
byteBuffer.flip();
channelWrite.write(byteBuffer);
}
fileOutputStream.close();
fileInputStream.close();
}
}
Selector(選擇器)(多路複用器)
1. Selector的建立
通過呼叫Selector.open()方法建立一個Selector物件,如下:
Selector selector = Selector.open();
2. 註冊Channel到Selector
channel.configureBlocking(false);
SelectionKey key = channel.register(selector, Selectionkey.OP_READ);
Channel必須是非阻塞的。
所以FileChannel不適用Selector,因為FileChannel不能切換為非阻塞模式,更準確的來說是因為FileChannel沒有繼承SelectableChannel。Socket channel可以正常使用。
SelectableChannel抽象類 有一個 configureBlocking() 方法用於使通道處於阻塞模式或非阻塞模式。
abstract SelectableChannel configureBlocking(boolean block)
示例程式碼
NIOServer端
public static void main(String[] args) throws IOException {
//得到serverSocketChannel物件 老大
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//得到Selector物件 間諜
Selector selector = Selector.open();
//繫結埠
serverSocketChannel.bind(new InetSocketAddress(9090));
//設定非阻塞式
serverSocketChannel.configureBlocking(false);
//把ServerSocketChannel註冊給Selector
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //監聽連線
//幹活
while (true) {
try {
//監控客戶端
if (selector.select(2000) == 0) {
System.out.println("2秒內沒有客戶端來連線我");
continue;
}
//得到SelectionKey物件,判斷是事件
Set<SelectionKey> selectionKeys = selector.selectedKeys();
for (SelectionKey selectionKey : selectionKeys) {
if (selectionKey.isAcceptable()) { //連線事件
System.out.println("有人來連線");
//獲取網路通道
SocketChannel clientSocket = serverSocketChannel.accept();
//設定非阻塞式
clientSocket.configureBlocking(false);
//連線上了 註冊讀取事件
clientSocket.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
}
if (selectionKey.isReadable()) { //讀取客戶端資料事件
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();
socketChannel.read(byteBuffer);
System.out.println(new String(byteBuffer.array()));
byteBuffer.put("你好".getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer);
}
if (selectionKey.isWritable()) {
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();
byteBuffer.put("你好".getBytes());
byteBuffer.clear();
socketChannel.write(byteBuffer);
selectionKey.interestOps(SelectionKey.OP_READ);
}
//手動從當前集合將本次執行完的物件刪除
selectionKeys.remove(selectionKey);
}
} catch (Exception e) {
System.out.println("錯了");
}
}
}
NIOClient客戶端
public static void main(String[] args) throws Exception {
//得到一個網路通道
SocketChannel socketChannel = SocketChannel.open();
//設定非阻塞式
socketChannel.configureBlocking(false);
//提供伺服器ip與埠
InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 9090);
//連線伺服器端
if (!socketChannel.connect(inetSocketAddress)) { //如果連線不上
while (!socketChannel.finishConnect()) {
System.out.println("nio非阻塞");
}
}
new Thread(new MyRunble(socketChannel)).start();
while (true) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
int read = socketChannel.read(buffer);
if (read > 0) {
System.out.println(new String(buffer.array()));
}
}
}
static class MyRunble implements Runnable {
SocketChannel socketChannel;
MyRunble(SocketChannel channel) {
this.socketChannel = channel;
}
@Override
public void run() {
while (true) {
//建立一個buffer物件並存入資料
Scanner scanner = new Scanner(System.in);
String message = scanner.nextLine();
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
//傳送資料
try {
socketChannel.write(buffer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
相關文章
- netty系列之:NIO和netty詳解Netty
- nio aio netty區別AINetty
- Netty原始碼分析--NIO(一)Netty原始碼
- 從BIO和NIO到Netty實踐Netty
- Netty(二)—— NIO 零拷貝機制Netty
- Netty | 第1章 Java NIO 網路程式設計《Netty In Action》NettyJava程式設計
- 深入學習Netty(一)NIO基礎篇Netty
- Netty-BIO、NIO、AIO、零複製-2NettyAI
- 從 BIO、NIO 到 Netty【前置知識點】Netty
- Netty雜記2—NIO網路程式設計Netty程式設計
- 深入學習Netty(2)——傳統NIO程式設計Netty程式設計
- (三)NIO元件Channel+ByteBuffer操作檔案【玩轉Netty系列】元件Netty
- Java網路程式設計和NIO詳解9:基於NIO的網路程式設計框架NettyJava程式設計框架Netty
- 分散式服務框架介紹:最成熟的開源NIO框架Netty分散式框架Netty
- 基於Java NIO 寫的一個簡單版 Netty 服務端JavaNetty服務端
- NIO
- 即時通訊技術文集(第9期):Java NIO和Netty入門系列 [共19篇]JavaNetty
- 那些你眼熟的武俠與言情封面,可能出自他們之手
- From BIO to NIO —— NIO source code interpretation 1
- 【死磕NIO】— NIO基礎詳解
- Java NIOJava
- NIO模型模型
- 網路程式設計NIO:BIO和NIO程式設計
- netty系列之:netty初探Netty
- Netty series: handling CORS in nettyNettyCORS
- 【譯】Java NIO 簡明教程系列之 NIO 概述Java
- JAVA NIO BufferJava
- NIO(一)概述
- JAVA 探究NIOJava
- Java NIO SocketChannelJava
- Java NIO - BufferJava
- Java NIO - 群聊Java
- Java NIO:通道Java
- BIO、NIO、AIOAI
- NIO基礎
- Java NIO filesJava
- NIO、BIO、Selector
- Netty1:初識NettyNetty