Java筆記之從IO模型到Netty框架學(xué)習(xí)初識篇
什么是Netty
- 異步,基于事件驅(qū)動的網(wǎng)絡(luò)應(yīng)用框架,用以快速開發(fā)高性能,高可靠的網(wǎng)絡(luò)IO程序
- 主要針對在TCP協(xié)議下,面向Clients端的高并發(fā)應(yīng)用
- 本質(zhì)是一個NIO框架,適用于服務(wù)器通訊等場景
異步:發(fā)送請求無需等待響應(yīng),程式接著往下走。
事件驅(qū)動:一個連接事件或者斷開事件,或者讀事件或者寫事件,發(fā)生后的后續(xù)處理。
Netty典型應(yīng)用:
- 高性能rpc框架用來遠程服務(wù)(過程)調(diào)用,比如Dubbo。
- 游戲行業(yè),頁面數(shù)據(jù)交互。
- 大數(shù)據(jù)領(lǐng)域如Hadoop高性能通訊和序列化組件(AVRO)。
IO模型
簡單理解就是用什么通道去進行數(shù)據(jù)發(fā)送和接收。
BIO:一個連接一個線程,連接不做任何事會造成不必要的線程開銷。適用于連接數(shù)目較小且固定的架構(gòu)。
NIO:服務(wù)端一個線程(也可以多個),維護一個多路復(fù)用器。由多路復(fù)用器去處理IO線程。適用于連接數(shù)目多且較短的架構(gòu)
AIO:異步非阻塞,還未得到廣泛應(yīng)用。適用于連接數(shù)目多且連接較長的架構(gòu)。
BIO
BIO編程簡單流程
- 服務(wù)端創(chuàng)建啟動ServerSocket
- 客戶端啟動Socket對服務(wù)器進行通信,默認服務(wù)器會對每一個客戶創(chuàng)建一個線程。
- 客戶端發(fā)出請求后,先咨詢線程是否有響應(yīng),如果沒有則等待或者拒絕。
- 如果有響應(yīng),則等待請求結(jié)束后,再繼續(xù)執(zhí)行。(阻塞)
BIO簡單實例
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ù)器啟動"); while(true){ //阻塞等待連接 Socket socket = serverSocket.accept(); System.out.println("連接到一個客戶端"); //每個連接對應(yīng)一個線程 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(); } }
測試:使用windows的telnet
使用 ctrl+]
?可以在服務(wù)端控制臺看到,已經(jīng)讀取到發(fā)送的數(shù)據(jù)
NIO
三大核心部分:Channel(可類比Socket),Buffer,Selector
大概是這個樣子。客戶端和Buffer交互,Buffer和Channel是一對一的關(guān)系。Selector選擇操作Channel(事件驅(qū)動,如果Channel有事件發(fā)生,Selector才去選擇操作。)
Buffer
Buffer基本使用
ByteBuffer使用場景較為廣泛。
buffer就是一個內(nèi)存塊,所以說nio是面向塊/緩沖,底層是數(shù)組。數(shù)據(jù)讀寫是通過buffer??梢允褂梅椒╢lip切換讀寫。
public class BufferNio { public static void main(String[] args) { //創(chuàng)建buffer容量為5個int IntBuffer buffer = IntBuffer.allocate(5); //放數(shù)據(jù) buffer.put(1); buffer.put(2); buffer.put(3); buffer.put(4); buffer.put(5); //讀寫切換 buffer.flip(); //取數(shù)據(jù) //內(nèi)部維護一個索引,每次get索引都會往后邊移動 while(buffer.hasRemaining()){ System.out.println(buffer.get()); } } }
Buffer四個主要屬性
// Invariants: mark <= position <= limit <= capacity private int mark = -1; private int position = 0; private int limit; private int capacity;
mark:標(biāo)記,很少改變
position:下一個要被讀元素的位置,為下次讀寫做準(zhǔn)備
limit:緩沖器當(dāng)前的終點,不能對緩沖區(qū)極限意外的區(qū)域讀寫,可變。
capacity:不可變,創(chuàng)建時指定的最大容量。
上邊出現(xiàn)了讀寫切換的方法flip,我們看下源碼,可以看出來通過改變屬性實現(xiàn)可讀可寫的。
public final Buffer flip() { limit = position; position = 0; mark = -1; return this; }
可以通過啊更改limit或者position來實現(xiàn)你想要的操作。參數(shù)自己決定
buffer.limit(2); buffer.position(1);
Channel
可讀可寫,上接Selector,下連Buffer。
當(dāng)客戶端連接ServerSocketChannel時,創(chuàng)建客戶端自己的SocketChannel。
本地文件寫案例
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寫入到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
用一個線程處理多個客戶端連接??梢詸z測多個注冊通道的事件,并作出相應(yīng)處理。不用維護所有線程。
Selector可以獲得被注冊的SocketChannel的一個SelectionKey集合,然后監(jiān)聽select,獲得有事件發(fā)生的SelectionKey,最后通過SelectionKey獲得通道進行相應(yīng)操作,完成業(yè)務(wù)。
到此這篇關(guān)于Java筆記之從IO模型到Netty框架學(xué)習(xí)初識篇的文章就介紹到這了,更多相關(guān)Java Netty框架內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring中的BeanFactory與FactoryBean的講解
今天小編就為大家分享一篇關(guān)于spring中的BeanFactory與FactoryBean的講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-01-01Java異步編程之Callbacks與Futures模型詳解
這篇文章主要為大家詳細介紹了Java異步編程中Callbacks與Futures模型的使用,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-03-03解決Java項目啟動報錯:Logback?configuration?error?detected:問題
這篇文章主要介紹了解決Java項目啟動報錯:Logback?configuration?error?detected:問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04使用SkyWalking監(jiān)控Java服務(wù)的過程
這篇文章主要介紹了使用SkyWalking監(jiān)控Java服務(wù),介紹一個對源碼0入侵的Java服務(wù)監(jiān)控方式,SkyWalking Agent,只需要啟動Java程序的時候加幾個參數(shù),就能對Java服務(wù)進行可視化監(jiān)控,需要的朋友可以參考下2023-08-08Spring的Aware接口實現(xiàn)及執(zhí)行順序詳解
這篇文章主要為大家介紹了Spring的Aware接口實現(xiàn)及執(zhí)行順序詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12springboot多數(shù)據(jù)源配置及切換的示例代碼詳解
這篇文章主要介紹了springboot多數(shù)據(jù)源配置及切換,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09