您好,登錄后才能下訂單哦!
這篇文章主要介紹“什么是Nginx、BIO、NIO、AIO”,在日常操作中,相信很多人在什么是Nginx、BIO、NIO、AIO問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”什么是Nginx、BIO、NIO、AIO”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
同步,一個任務的完成之前不能做其他操作,必須等待(等于在打電話)
異步,一個任務的完成之前,可以進行其他操作(等于在聊QQ)
阻塞,是相對于CPU來說的, 掛起當前線程,不能做其他操作只能等待
非阻塞,,無須掛起當前線程,可以去執行其他操作
BIO:同步并阻塞,服務器實現一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程進行處理,沒處理完之前此線程不能做其他操作(如果是單線程的情況下,我傳輸的文件很大呢?),當然可以通過線程池機制改善。BIO方式適用于連接數目比較小且固定的架構,這種方式對服務器資源要求比較高,并發局限于應用中,JDK1.4以前的唯一選擇,但程序直觀簡單易理解。
NIO:同步非阻塞,服務器實現一個連接一個線程,即客戶端發送的連接請求都會注冊到多路復用器上,多路復用器輪詢到連接有I/O請求時才啟動一個線程進行處理。NIO方式適用于連接數目多且連接比較短(輕操作)的架構,比如聊天服務器,并發局限于應用中,編程比較復雜,JDK1.4之后開始支持。
AIO:異步非阻塞,服務器實現模式為一個有效請求一個線程,客戶端的I/O請求都是由操作系統先完成了再通知服務器應用去啟動線程進行處理,AIO方式使用于連接數目多且連接比較長(重操作)的架構,比如相冊服務器,充分調用操作系統參與并發操作,編程比較復雜,JDK1.7之后開始支持。.
AIO屬于NIO包中的類實現,其實IO主要分為BIO和NIO,AIO只是附加品,解決IO不能異步的實現
在以前很少有Linux系統支持AIO,Windows的IOCP就是該AIO模型。但是現在的服務器一般都是支持AIO操作
BIO是阻塞的,NIO是非阻塞的.
BIO是面向流的,只能單向讀寫,NIO是面向緩沖的, 可以雙向讀寫
使用BIO做Socket連接時,由于單向讀寫,當沒有數據時,會掛起當前線程,阻塞等待,為防止影響其它連接,,需要為每個連接新建線程處理.,然而系統資源是有限的,,不能過多的新建線程,線程過多帶來線程上下文的切換,從來帶來更大的性能損耗,因此需要使用NIO進行BIO多路復用,使用一個線程來監聽所有Socket連接,使用本線程或者其他線程處理連接
AIO是非阻塞 以異步方式發起 I/O 操作。當 I/O 操作進行時可以去做其他操作,由操作系統內核空間提醒IO操作已完成(不懂的可以往下看)
注意:我這里的用戶空間就是應用程序空間
B也在河邊釣魚,但是B不想將自己的所有時間都花費在釣魚上,在等魚上鉤這個時間段中,B也在做其他的事情(一會看看書,一會讀讀報紙,一會又去看其他人的釣魚等),但B在做這些事情的時候,每隔一個固定的時間檢查魚是否上鉤。一旦檢查到有魚上鉤,就停下手中的事情,把魚釣上來。 B在檢查魚竿是否有魚,是一個輪詢的過程。
G也在河邊釣魚,但與A、B、C不同的是,G比較聰明,他給魚竿上掛一個鈴鐺,當有魚上鉤的時候,這個鈴鐺就會被碰響,G就會將魚釣上來。
Bit最小的二進制單位 ,是計算機的操作部分取值0或者1
Byte是計算機中存儲數據的單元,是一個8位的二進制數,(計算機內部,一個字節可表示一個英文字母,兩個字節可表示一個漢字。) 取值(-128-127)
Char是用戶的可讀寫的最小單位,他只是抽象意義上的一個符號。如‘5’,‘中’,‘¥’ 等等等等。在java里面由16位bit組成Char 取值 (0-65535)
Bit 是最小單位 計算機他只能認識0或者1
Byte是8個字節 是給計算機看的
字符 是看到的東西 一個字符=二個字節
對象序列化,將對象以二進制的形式保存在硬盤上
反序列化;將二進制的文件轉化為對象讀取
實現serializable接口,不想讓字段放在硬盤上就加transient
如果用戶沒有自己聲明一個serialVersionUID,接口會默認生成一個serialVersionUID
但是強烈建議用戶自定義一個serialVersionUID,因為默認的serialVersinUID對于class的細節非常敏感,反序列化時可能會導致InvalidClassException這個異常。
(比如說先進行序列化,然后在反序列化之前修改了類,那么就會報錯。因為修改了類,對應的SerialversionUID也變化了,而序列化和反序列化就是通過對比其SerialversionUID來進行的,一旦SerialversionUID不匹配,反序列化就無法成功。
屬于處理流中的緩沖流,可以將讀取的內容存在內存里面,有readLine()方法
超類代表頂端的父類(都是抽象類)
java.io.InputStream
java.io.OutputStream
java.io.Reader
java.io.Writer
這里的基本操作就是普通的讀取操作,如果想要跟深入的了解不同的IO開發場景必須先了解IO的基本操作
我這使用Socket簡單的來模擬網絡編程IO會帶來的問題
不懂Socket可以看我之前的文章,這個東西很容易懂的,就是基于TCP實現的網絡通信,比http要快,很多實現網絡通信的框架都是基于Socket來實現
package com.test.io; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; //TCP協議Socket使用BIO進行通信:服務端 public class BIOServer { // 在main線程中執行下面這些代碼 public static void main(String[] args) { //使用Socket進行網絡通信 ServerSocket server = null; Socket socket = null; //基于字節流 InputStream in = null; OutputStream out = null; try { server = new ServerSocket(8000); System.out.println("服務端啟動成功,監聽端口為8000,等待客戶端連接..."); while (true){ socket = server.accept(); //等待客戶端連接 System.out.println("客戶連接成功,客戶信息為:" + socket.getRemoteSocketAddress()); in = socket.getInputStream(); byte[] buffer = new byte[1024]; int len = 0; //讀取客戶端的數據 while ((len = in.read(buffer)) > 0) { System.out.println(new String(buffer, 0, len)); } //向客戶端寫數據 out = socket.getOutputStream(); out.write("hello!".getBytes()); } } catch (IOException e) { e.printStackTrace(); } } } TCP協議Socket使用BIO進行通信:客戶端(第二執行) package com.test.io; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.util.Scanner; //TCP協議Socket使用BIO進行通信:客戶端 public class Client01 { public static void main(String[] args) throws IOException { //創建套接字對象socket并封裝ip與port Socket socket = new Socket("127.0.0.1", 8000); //根據創建的socket對象獲得一個輸出流 //基于字節流 OutputStream outputStream = socket.getOutputStream(); //控制臺輸入以IO的形式發送到服務器 System.out.println("TCP連接成功 \n請輸入:"); String str = new Scanner(System.in).nextLine(); byte[] car = str.getBytes(); outputStream.write(car); System.out.println("TCP協議的Socket發送成功"); //刷新緩沖區 outputStream.flush(); //關閉連接 socket.close(); } } package com.test.io; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.util.Scanner; //TCP協議Socket:客戶端 public class Client02 { public static void main(String[] args) throws IOException { //創建套接字對象socket并封裝ip與port Socket socket = new Socket("127.0.0.1", 8000); //根據創建的socket對象獲得一個輸出流 //基于字節流 OutputStream outputStream = socket.getOutputStream(); //控制臺輸入以IO的形式發送到服務器 System.out.println("TCP連接成功 \n請輸入:"); String str = new Scanner(System.in).nextLine(); byte[] car = str.getBytes(); outputStream.write(car); System.out.println("TCP協議的Socket發送成功"); //刷新緩沖區 outputStream.flush(); //關閉連接 socket.close(); } }
為了解決堵塞問題,可以使用多線程,請看下面
這時有人就會說,我多線程不就解決了嗎?
使用多線程是可以解決堵塞等待時間很長的問題,因為他可以充分發揮CPU
然而系統資源是有限的,不能過多的新建線程,線程過多帶來線程上下文的切換,從來帶來更大的性能損耗
package com.test.io; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; //TCP協議Socket使用多線程BIO進行通行:服務端 public class BIOThreadService { public static void main(String[] args) { try { ServerSocket server = new ServerSocket(8000); System.out.println("服務端啟動成功,監聽端口為8000,等待客戶端連接... "); while (true) { Socket socket = server.accept();//等待客戶連接 System.out.println("客戶連接成功,客戶信息為:" + socket.getRemoteSocketAddress()); //針對每個連接創建一個線程, 去處理I0操作 //創建多線程創建開始 Thread thread = new Thread(new Runnable() { public void run() { try { InputStream in = socket.getInputStream(); byte[] buffer = new byte[1024]; int len = 0; //讀取客戶端的數據 while ((len = in.read(buffer)) > 0) { System.out.println(new String(buffer, 0, len)); } //向客戶端寫數據 OutputStream out = socket.getOutputStream(); out.write("hello".getBytes()); } catch (IOException e) { e.printStackTrace(); } } }); thread.start(); } } catch (IOException e) { e.printStackTrace(); } } }
為了解決線程太多,這時又來了,線程池
package com.test.io; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; //TCP協議Socket使用線程池BIO進行通行:服務端 public class BIOThreadPoolService { public static void main(String[] args) { //創建線程池 ExecutorService executorService = Executors.newFixedThreadPool(30); try { ServerSocket server = new ServerSocket(8000); System.out.println("服務端啟動成功,監聽端口為8000,等待客戶端連接..."); while (true) { Socket socket = server.accept(); //等待客戶連接 System.out.println("客戶連接成功,客戶信息為:" + socket.getRemoteSocketAddress()); //使用線程池中的線程去執行每個對應的任務 executorService.execute(new Thread(new Runnable() { public void run() { try { InputStream in = socket.getInputStream(); byte[] buffer = new byte[1024]; int len = 0; //讀取客戶端的數據 while ((len = in.read(buffer)) > 0) { System.out.println(new String(buffer, 0, len)); } //向客戶端寫數據 OutputStream out = socket.getOutputStream(); out.write("hello".getBytes()); } catch (IOException e) { e.printStackTrace(); } } } ) ); } } catch (IOException e) { e.printStackTrace(); } } }
package com.test.io; import com.lijie.iob.RequestHandler; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set; public class NIOServer { public static void main(String[] args) throws IOException { //111111111 //Service端的Channel,監聽端口的 ServerSocketChannel serverChannel = ServerSocketChannel.open(); //設置為非阻塞 serverChannel.configureBlocking(false); //nio的api規定這樣賦值端口 serverChannel.bind(new InetSocketAddress(8000)); //顯示Channel是否已經啟動成功,包括綁定在哪個地址上 System.out.println("服務端啟動成功,監聽端口為8000,等待客戶端連接..."+ serverChannel.getLocalAddress()); //22222222 //聲明selector選擇器 Selector selector = Selector.open(); //這句話的含義,是把selector注冊到Channel上面, //每個客戶端來了之后,就把客戶端注冊到Selector選擇器上,默認狀態是Accepted serverChannel.register(selector, SelectionKey.OP_ACCEPT); //33333333 //創建buffer緩沖區,聲明大小是1024,底層使用數組來實現的 ByteBuffer buffer = ByteBuffer.allocate(1024); RequestHandler requestHandler = new RequestHandler(); //444444444 //輪詢,服務端不斷輪詢,等待客戶端的連接 //如果有客戶端輪詢上來就取出對應的Channel,沒有就一直輪詢 while (true) { int select = selector.select(); if (select == 0) { continue; } //有可能有很多,使用Set保存Channel Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> iterator = selectionKeys.iterator(); while (iterator.hasNext()) { //使用SelectionKey來獲取連接了客戶端和服務端的Channel SelectionKey key = iterator.next(); //判斷SelectionKey中的Channel狀態如何,如果是OP_ACCEPT就進入 if (key.isAcceptable()) { //從判斷SelectionKey中取出Channel ServerSocketChannel channel = (ServerSocketChannel) key.channel(); //拿到對應客戶端的Channel SocketChannel clientChannel = channel.accept(); //把客戶端的Channel打印出來 System.out.println("客戶端通道信息打印:" + clientChannel.getRemoteAddress()); //設置客戶端的Channel設置為非阻塞 clientChannel.configureBlocking(false); //操作完了改變SelectionKey中的Channel的狀態OP_READ clientChannel.register(selector, SelectionKey.OP_READ); } //到此輪訓到的時候,發現狀態是read,開始進行數據交互 if (key.isReadable()) { //以buffer作為數據橋梁 SocketChannel channel = (SocketChannel) key.channel(); //數據要想讀要先寫,必須先讀取到buffer里面進行操作 channel.read(buffer); //進行讀取 String request = new String(buffer.array()).trim(); buffer.clear(); //進行打印buffer中的數據 System.out.println(String.format("客戶端發來的消息: %s : %s", channel.getRemoteAddress(), request)); //要返回數據的話也要先返回buffer里面進行返回 String response = requestHandler.handle(request); //然后返回出去 channel.write(ByteBuffer.wrap(response.getBytes())); } iterator.remove(); } } } }
package com.test.io; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.util.Scanner; //TCP協議Socket:客戶端 public class Client01 { public static void main(String[] args) throws IOException { //創建套接字對象socket并封裝ip與port Socket socket = new Socket("127.0.0.1", 8000); //根據創建的socket對象獲得一個輸出流 OutputStream outputStream = socket.getOutputStream(); //控制臺輸入以IO的形式發送到服務器 System.out.println("TCP連接成功 n請輸入:"); while(true){ byte[] car = new Scanner(System.in).nextLine().getBytes(); outputStream.write(car); System.out.println("TCP協議的Socket發送成功"); //刷新緩沖區 outputStream.flush(); } } }
Netty是由JBOSS提供的一個Java開源框架。Netty提供異步的、事件驅動的網絡應用程序框架和工具,用以快速開發高性能、高可靠性的網絡服務器和客戶端程序。
Netty 是一個基于NIO的客戶、服務器端編程框架,使用Netty 可以確保你快速和簡單的開發出一個網絡應用,例如實現了某種協議的客戶,服務端應用。Netty相當簡化和流線化了網絡應用的編程開發過程,例如,TCP和UDP的Socket服務開發。
到此,關于“什么是Nginx、BIO、NIO、AIO”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。