您好,登錄后才能下訂單哦!
這篇文章主要介紹“Java的IO模型和Netty框架是什么”,在日常操作中,相信很多人在Java的IO模型和Netty框架是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java的IO模型和Netty框架是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
異步,基于事件驅動的網絡應用框架,用以快速開發高性能,高可靠的網絡IO程序
主要針對在TCP協議下,面向Clients端的高并發應用
本質是一個NIO框架,適用于服務器通訊等場景
異步:發送請求無需等待響應,程式接著往下走。
事件驅動:一個連接事件或者斷開事件,或者讀事件或者寫事件,發生后的后續處理。
Netty典型應用:
高性能rpc框架用來遠程服務(過程)調用,比如Dubbo。
游戲行業,頁面數據交互。
大數據領域如Hadoop高性能通訊和序列化組件(AVRO)。
簡單理解就是用什么通道去進行數據發送和接收。
BIO:一個連接一個線程,連接不做任何事會造成不必要的線程開銷。適用于連接數目較小且固定的架構。
NIO:服務端一個線程(也可以多個),維護一個多路復用器。由多路復用器去處理IO線程。適用于連接數目多且較短的架構
AIO:異步非阻塞,還未得到廣泛應用。適用于連接數目多且連接較長的架構。
服務端創建啟動ServerSocket
客戶端啟動Socket對服務器進行通信,默認服務器會對每一個客戶創建一個線程。
客戶端發出請求后,先咨詢線程是否有響應,如果沒有則等待或者拒絕。
如果有響應,則等待請求結束后,再繼續執行。(阻塞)
public class BIOserver { public static void main(String[] args) throws IOException { // 為了方便直接用了Executors創建線程池 ExecutorService service = Executors.newCachedThreadPool(); //指定服務端端口 ServerSocket serverSocket = new ServerSocket(6666); System.out.println("服務器啟動"); while(true){ //阻塞等待連接 Socket socket = serverSocket.accept(); System.out.println("連接到一個客戶端"); //每個連接對應一個線程 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+]
可以在服務端控制臺看到,已經讀取到發送的數據
三大核心部分:Channel(可類比Socket),Buffer,Selector
大概是這個樣子。客戶端和Buffer交互,Buffer和Channel是一對一的關系。Selector選擇操作Channel(事件驅動,如果Channel有事件發生,Selector才去選擇操作。)
ByteBuffer使用場景較為廣泛。
buffer就是一個內存塊,所以說nio是面向塊/緩沖,底層是數組。數據讀寫是通過buffer。可以使用方法flip切換讀寫。
public class BufferNio { public static void main(String[] args) { //創建buffer容量為5個int IntBuffer buffer = IntBuffer.allocate(5); //放數據 buffer.put(1); buffer.put(2); buffer.put(3); buffer.put(4); buffer.put(5); //讀寫切換 buffer.flip(); //取數據 //內部維護一個索引,每次get索引都會往后邊移動 while(buffer.hasRemaining()){ System.out.println(buffer.get()); } } }
// Invariants: mark <= position <= limit <= capacity private int mark = -1; private int position = 0; private int limit; private int capacity;
mark:標記,很少改變
position:下一個要被讀元素的位置,為下次讀寫做準備
limit:緩沖器當前的終點,不能對緩沖區極限意外的區域讀寫,可變。
capacity:不可變,創建時指定的最大容量。
上邊出現了讀寫切換的方法flip,我們看下源碼,可以看出來通過改變屬性實現可讀可寫的。
public final Buffer flip() { limit = position; position = 0; mark = -1; return this; }
可以通過啊更改limit或者position來實現你想要的操作。參數自己決定
buffer.limit(2); buffer.position(1);
可讀可寫,上接Selector,下連Buffer。
當客戶端連接ServerSocketChannel時,創建客戶端自己的SocketChannel。
public class ChannelNio { public static void main(String[] args) throws IOException { String str = "少壯不努力,老大徒傷悲"; //創建輸出流 FileOutputStream os = new FileOutputStream("D:\\xxxxxxxxxxxxxxxxxxx\\a.txt"); //獲取FileChannel FileChannel channel = os.getChannel(); //創建緩沖 ByteBuffer buffer = ByteBuffer.allocate(1024); //把字符串放入緩沖區 buffer.put(str.getBytes()); //反轉ByteBuffer buffer.flip(); //將ByteBuffer寫入到FileChannel channel.write(buffer); //關閉流 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可以獲得被注冊的SocketChannel的一個SelectionKey集合,然后監聽select,獲得有事件發生的SelectionKey,最后通過SelectionKey獲得通道進行相應操作,完成業務。
到此,關于“Java的IO模型和Netty框架是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。