Java筆記之從IO模型到Netty框架學(xué)習(xí)初識(shí)篇
什么是Netty
- 異步,基于事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用框架,用以快速開(kāi)發(fā)高性能,高可靠的網(wǎng)絡(luò)IO程序
- 主要針對(duì)在TCP協(xié)議下,面向Clients端的高并發(fā)應(yīng)用
- 本質(zhì)是一個(gè)NIO框架,適用于服務(wù)器通訊等場(chǎng)景
異步:發(fā)送請(qǐng)求無(wú)需等待響應(yīng),程式接著往下走。
事件驅(qū)動(dòng):一個(gè)連接事件或者斷開(kāi)事件,或者讀事件或者寫(xiě)事件,發(fā)生后的后續(xù)處理。

Netty典型應(yīng)用:
- 高性能rpc框架用來(lái)遠(yuǎn)程服務(wù)(過(guò)程)調(diào)用,比如Dubbo。
- 游戲行業(yè),頁(yè)面數(shù)據(jù)交互。
- 大數(shù)據(jù)領(lǐng)域如Hadoop高性能通訊和序列化組件(AVRO)。
IO模型
簡(jiǎn)單理解就是用什么通道去進(jìn)行數(shù)據(jù)發(fā)送和接收。
BIO:一個(gè)連接一個(gè)線程,連接不做任何事會(huì)造成不必要的線程開(kāi)銷。適用于連接數(shù)目較小且固定的架構(gòu)。

NIO:服務(wù)端一個(gè)線程(也可以多個(gè)),維護(hù)一個(gè)多路復(fù)用器。由多路復(fù)用器去處理IO線程。適用于連接數(shù)目多且較短的架構(gòu)

AIO:異步非阻塞,還未得到廣泛應(yīng)用。適用于連接數(shù)目多且連接較長(zhǎng)的架構(gòu)。
BIO
BIO編程簡(jiǎn)單流程
- 服務(wù)端創(chuàng)建啟動(dòng)ServerSocket
- 客戶端啟動(dòng)Socket對(duì)服務(wù)器進(jìn)行通信,默認(rèn)服務(wù)器會(huì)對(duì)每一個(gè)客戶創(chuàng)建一個(gè)線程。
- 客戶端發(fā)出請(qǐng)求后,先咨詢線程是否有響應(yīng),如果沒(méi)有則等待或者拒絕。
- 如果有響應(yīng),則等待請(qǐng)求結(jié)束后,再繼續(xù)執(zhí)行。(阻塞)
BIO簡(jiǎn)單實(shí)例
public class BIOserver {
public static void main(String[] args) throws IOException {
// 為了方便直接用了Executors創(chuàng)建線程池
ExecutorService service = Executors.newCachedThreadPool();
//指定服務(wù)端端口
ServerSocket serverSocket = new ServerSocket(6666);
System.out.println("服務(wù)器啟動(dòng)");
while(true){
//阻塞等待連接
Socket socket = serverSocket.accept();
System.out.println("連接到一個(gè)客戶端");
//每個(gè)連接對(duì)應(yīng)一個(gè)線程
service.execute(new Runnable() {
@Override
public void run() {
try {
handler(socket);
}catch (Exception e){
e.printStackTrace();
}
}
});
}
}
public static void handler(Socket socket) throws IOException {
System.out.println("Thread:"+Thread.currentThread().getId());
byte[] bytes = new byte[1024];
InputStream inputStream = socket.getInputStream();
while (true){
//阻塞等待讀取
int n = inputStream.read(bytes);
if(n!=-1){
System.out.println(new String(bytes,0,n));
}else {
break;
}
}
socket.close();
}
}
測(cè)試:使用windows的telnet
![]()
使用 ctrl+]

![]()
?可以在服務(wù)端控制臺(tái)看到,已經(jīng)讀取到發(fā)送的數(shù)據(jù)

NIO
三大核心部分:Channel(可類比Socket),Buffer,Selector
大概是這個(gè)樣子??蛻舳撕虰uffer交互,Buffer和Channel是一對(duì)一的關(guān)系。Selector選擇操作Channel(事件驅(qū)動(dòng),如果Channel有事件發(fā)生,Selector才去選擇操作。)

Buffer
Buffer基本使用
ByteBuffer使用場(chǎng)景較為廣泛。
buffer就是一個(gè)內(nèi)存塊,所以說(shuō)nio是面向塊/緩沖,底層是數(shù)組。數(shù)據(jù)讀寫(xiě)是通過(guò)buffer。可以使用方法flip切換讀寫(xiě)。
public class BufferNio {
public static void main(String[] args) {
//創(chuàng)建buffer容量為5個(gè)int
IntBuffer buffer = IntBuffer.allocate(5);
//放數(shù)據(jù)
buffer.put(1);
buffer.put(2);
buffer.put(3);
buffer.put(4);
buffer.put(5);
//讀寫(xiě)切換
buffer.flip();
//取數(shù)據(jù)
//內(nèi)部維護(hù)一個(gè)索引,每次get索引都會(huì)往后邊移動(dòng)
while(buffer.hasRemaining()){
System.out.println(buffer.get());
}
}
}
Buffer四個(gè)主要屬性
// Invariants: mark <= position <= limit <= capacity
private int mark = -1;
private int position = 0;
private int limit;
private int capacity;
mark:標(biāo)記,很少改變
position:下一個(gè)要被讀元素的位置,為下次讀寫(xiě)做準(zhǔn)備
limit:緩沖器當(dāng)前的終點(diǎn),不能對(duì)緩沖區(qū)極限意外的區(qū)域讀寫(xiě),可變。
capacity:不可變,創(chuàng)建時(shí)指定的最大容量。
上邊出現(xiàn)了讀寫(xiě)切換的方法flip,我們看下源碼,可以看出來(lái)通過(guò)改變屬性實(shí)現(xiàn)可讀可寫(xiě)的。
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
可以通過(guò)啊更改limit或者position來(lái)實(shí)現(xiàn)你想要的操作。參數(shù)自己決定
buffer.limit(2);
buffer.position(1);
Channel
可讀可寫(xiě),上接Selector,下連Buffer。
當(dāng)客戶端連接ServerSocketChannel時(shí),創(chuàng)建客戶端自己的SocketChannel。
本地文件寫(xiě)案例
public class ChannelNio {
public static void main(String[] args) throws IOException {
String str = "少壯不努力,老大徒傷悲";
//創(chuàng)建輸出流
FileOutputStream os = new FileOutputStream("D:\\xxxxxxxxxxxxxxxxxxx\\a.txt");
//獲取FileChannel
FileChannel channel = os.getChannel();
//創(chuàng)建緩沖
ByteBuffer buffer = ByteBuffer.allocate(1024);
//把字符串放入緩沖區(qū)
buffer.put(str.getBytes());
//反轉(zhuǎn)ByteBuffer
buffer.flip();
//將ByteBuffer寫(xiě)入到FileChannel
channel.write(buffer);
//關(guān)閉流
os.close();
}
}
圖示理解

本地文件讀案例
public class ChannelNio {
public static void main(String[] args) throws IOException {
FileInputStream is = new FileInputStream("D:\\xxxxxxxxxxxxxxxxxxx\\a.txt");
FileChannel channel = is.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);
System.out.println(new String(buffer.array()));
is.close();
}
}
本地文件拷貝案例
方法一
public class ChannelNio {
public static void main(String[] args) throws IOException {
FileInputStream is = new FileInputStream("D:\\xxxxxxxxxxxxxxxxxxx\\a.txt");
FileChannel channel = is.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
FileOutputStream os = new FileOutputStream("D:\\xxxxxxxxxxxxxxxxxxx\\b.txt");
FileChannel osChannel = os.getChannel();
while (true){
buffer.clear();
int i = channel.read(buffer);
if(i==-1){
break;
}
buffer.flip();
osChannel.write(buffer);
}
is.close();
os.close();
}
}
方法二
public class ChannelNio {
public static void main(String[] args) throws IOException {
FileInputStream is = new FileInputStream("D:\\xxxxxxxxxxxxxxxxxxx\\HELP.md");
FileChannel channel = is.getChannel();
FileOutputStream os = new FileOutputStream("D:\\xxxxxxxxxxxxxxxxxxx\\HELP222.md");
FileChannel osChannel = os.getChannel();
osChannel.transferFrom(channel,0,channel.size());
is.close();
os.close();
}
}
Selector
用一個(gè)線程處理多個(gè)客戶端連接。可以檢測(cè)多個(gè)注冊(cè)通道的事件,并作出相應(yīng)處理。不用維護(hù)所有線程。

Selector可以獲得被注冊(cè)的SocketChannel的一個(gè)SelectionKey集合,然后監(jiān)聽(tīng)select,獲得有事件發(fā)生的SelectionKey,最后通過(guò)SelectionKey獲得通道進(jìn)行相應(yīng)操作,完成業(yè)務(wù)。
到此這篇關(guān)于Java筆記之從IO模型到Netty框架學(xué)習(xí)初識(shí)篇的文章就介紹到這了,更多相關(guān)Java Netty框架內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java設(shè)置Map過(guò)期時(shí)間的的幾種方法舉例詳解
本文詳細(xì)介紹了Java中使用輕量級(jí)緩存組件ExpiringMap以及Guava的LoadingCache緩存機(jī)制,ExpiringMap提供了Map自動(dòng)過(guò)期、監(jiān)聽(tīng)事件等功能,而LoadingCache提供了緩存回收、數(shù)據(jù)加載等高級(jí)功能,兩者為Java項(xiàng)目提供了有效的數(shù)據(jù)管理和緩存解決方案,需要的朋友可以參考下2024-10-10
SpringBoot結(jié)合Maven項(xiàng)目依賴版本沖突問(wèn)題解決
本文主要介紹了SpringBoot結(jié)合Maven項(xiàng)目依賴版本沖突問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
java保證一個(gè)方法只能執(zhí)行一次的問(wèn)題
這篇文章主要介紹了java保證一個(gè)方法只能執(zhí)行一次的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
解決rror updating database.Cause:java.sql.SQLSyntaxE
這篇文章主要介紹了解決rror updating database.Cause:java.sql.SQLSyntaxErrorException問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
maven基礎(chǔ)教程——簡(jiǎn)單了解maven的特點(diǎn)與功能
這篇文章主要介紹了Maven基礎(chǔ)教程的相關(guān)資料,文中講解非常細(xì)致,幫助大家開(kāi)始學(xué)習(xí)maven,感興趣的朋友可以了解下2020-07-07
Java Swing中的文本區(qū)(JTextArea)實(shí)現(xiàn)換行保存到文件的幾個(gè)方法
這篇文章主要介紹了Java Swing中的文本區(qū)(JTextArea)實(shí)現(xiàn)換行保存到文件的幾個(gè)方法,本文給出了4種方法,需要的朋友可以參考下2014-10-10

