成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

從I/O多路復用到Netty,還要跨過Java NIO包

網絡 網絡管理
Netty實際上也是一個封裝好的框架,它的網絡I/O本質上還是使用了Java的NIO包(New IO,不是網絡I/O模型的NIO,Nonblocking IO)包。所以,從網絡I/O模型到Netty,我們還需要了解下Java NIO包。

[[389262]]

上一篇文章我們深入了解了I/O多路復用的三種實現形式,select/poll/epoll。

那Netty是使用哪種實現的I/O多路復用呢?這個問題,得從Java NIO包說起。

Netty實際上也是一個封裝好的框架,它的網絡I/O本質上還是使用了Java的NIO包(New IO,不是網絡I/O模型的NIO,Nonblocking IO)包。所以,從網絡I/O模型到Netty,我們還需要了解下Java NIO包。

本文預計閱讀時間 5 分鐘,將重點回答以下幾個問題:

  • 如何用Java NIO包實現一個服務端
  • Java NIO包如何實現I/O多路復用模型
  • 有了Java NIO包,為什么還要封裝一個Netty?

1.先來看一個Java NIO服務端的例子

上一篇文章我們已經了解了I/O多路復用的實現形式。

就是多個的進程的IO可以注冊到一個復用器(selector)上,然后用一個進程調用select,select會監聽所有注冊進來的IO。

NIO包做了對應的實現。如下圖所示。


有一個統一的selector負責監聽所有的Channel。這些channel中只要有一個有IO動作,就可以通過Selector.select()方法檢測到,并且使用selectedKeys得到這些有IO的channel,然后對它們調用相應的IO操作。

我們來個簡單的demo做一下演示。如何使用NIO中三個核心組件(Buffer緩沖區、Channel通道、Selector選擇器)來編寫一個服務端程序。

  1. public class NioDemo { 
  2.     public static void main(String[] args) { 
  3.         try { 
  4.             //1.創建channel 
  5.             ServerSocketChannel socketChannel1 = ServerSocketChannel.open(); 
  6.             //設置為非阻塞模式,默認是阻塞的 
  7.             socketChannel1.configureBlocking(false); 
  8.             socketChannel1.socket().bind(new InetSocketAddress("127.0.0.1", 8811)); 
  9.  
  10.             ServerSocketChannel socketChannel2 = ServerSocketChannel.open(); 
  11.             socketChannel2.configureBlocking(false); 
  12.             socketChannel2.socket().bind(new InetSocketAddress("127.0.0.1", 8822)); 
  13.  
  14.             //2.創建selector,并將channel1和channel2進行注冊。 
  15.             Selector selector = Selector.open(); 
  16.             socketChannel1.register(selector, SelectionKey.OP_ACCEPT); 
  17.             socketChannel2.register(selector, SelectionKey.OP_ACCEPT); 
  18.  
  19.             while (true) { 
  20.                 //3.一直阻塞直到有至少有一個通道準備就緒 
  21.                 int readChannelCount = selector.select(); 
  22.                 Set<SelectionKey> selectionKeys = selector.selectedKeys(); 
  23.                 Iterator<SelectionKey> iterator = selectionKeys.iterator(); 
  24.                 //4.輪訓已經就緒的通道 
  25.                 while (iterator.hasNext()) { 
  26.                     SelectionKey key = iterator.next(); 
  27.                     iterator.remove(); 
  28.                     //5.判斷準備就緒的事件類型,并作相應處理 
  29.                     if (key.isAcceptable()) { 
  30.                         // 創建新的連接,并且把連接注冊到selector上,并且聲明這個channel只對讀操作感興趣。 
  31.                         ServerSocketChannel serverSocketChannel = (ServerSocketChannel)key.channel(); 
  32.                         SocketChannel socketChannel = serverSocketChannel.accept(); 
  33.                         socketChannel.configureBlocking(false); 
  34.                         socketChannel.register(selector, SelectionKey.OP_READ); 
  35.                     } 
  36.                     if (key.isReadable()) { 
  37.                         SocketChannel socketChannel = (SocketChannel) key.channel(); 
  38.                         ByteBuffer readBuff = ByteBuffer.allocate(1024); 
  39.                         socketChannel.read(readBuff); 
  40.                         readBuff.flip(); 
  41.                         System.out.println("received : " + new String(readBuff.array())); 
  42.                         socketChannel.close(); 
  43.                     } 
  44.                 } 
  45.             } 
  46.         } catch (IOException e) { 
  47.             e.printStackTrace(); 
  48.         } 
  49.     } 

通過這個代碼示例,我們能清楚地了解如何用Java NIO包實現一個服務端:

  • 1)創建channel1和channel2,分別監聽特定端口。
  • 2)創建selector,并將channel1和channel2進行注冊。
  • 3)selector.select()一直阻塞,直到有至少有一個通道準備就緒。
  • 4)輪訓已經就緒的通道
  • 5)并根據事件類型做出相應的響應動作。程序啟動后,會一直阻塞在selector.select()。

通過瀏覽器調用localhost:8811 或者 localhost:8822就能觸發我們的服務端代碼了。

2.Java NIO包如何實現I/O多路復用模型

上文演示的Java NIO服務端已經比較清楚地展示了使用NIO編寫服務端程序的過程。

那這個過程中如何實現了I/O多路復用的呢?

我們得深入看下selector的實現。

  1. //2.創建selector,并將channel1和channel2進行注冊。 
  2. Selector selector = Selector.open(); 

從open這里開始吧。


這里用了一個SelectorProvider來創建selector。

進入SelectorProvider.provider(),看到具體的provider是由

sun.nio.ch.DefaultSelectorProvider創建的,對應的方法是:


咦?原來不同的操作系統會提供不同的provider對象。這里包括了PollSelectorProvider、EPollSelectorProvide等。

名字是不是有點眼熟?

沒錯,跟我們上一篇文章分析過的I/O多路復用的不同實現方式poll/epoll有關。

我們選擇默認的

sun.nio.ch.PollSelectorProvider往下看看。


OK,找到了實現類PollSelectorImpl。

然后,通過以下調用:


找到最終的native方法poll0。


是不是仍然很眼熟?

沒錯!跟我們上一篇文章分析過的poll函數是一致的。

  1. int poll (struct pollfd *fds, unsigned int nfds, int timeout); 

繞了這么久,到最后,還是找到了我們聊過I/O多路復用的 poll 實現。

至此,我們終于把Java NIO和 I/O多路復用模型串聯起來了。

Java NIO包使用selector,實現了I/O多路復用模型。

同時,在不同的操作系統中,會有不同的poll/epoll選擇。

3.為什么還需要Netty呢?

那既然已經有了NIO包了,我們可以自己手動編寫服務框架了,為什么還需要封裝一個Netty框架呢?有什么好處呢?

好處當然是有很多了!我們從一開始實現的demo說起。

3.1 設計模式的優化

我們的demo確實已經能夠工作了,但是還是有比較明顯的問題。第4步(輪詢已經就緒的通道)和第5步(對事件作相應處理)是在同一個線程中的,當事件處理比較耗時甚至阻塞時,整個流程就會阻塞了。

我們使用的實際上就是 “單Reactor單線程” 設計模式。


這種模型在Reactor中負責監聽端口、接收請求,如果是連接事件交給acceptor處理,如果是讀寫事件和業務處理就交給handler處理,但始終只有一個線程執行所有的事情。

為了提高性能,我們理所當然相當可以把事件處理交給線程池,那就可以演進為 “單Reactor多線程” 設計模式。


這種模型和第一種模型的主要區別是把業務處理從之前的單一線程脫離出來,換成線程池處理。Reactor線程只處理連接事件、讀寫事件,所有業務處理都交給線程池,充分利用多核機器的資源,提高性能。

但是這仍然不夠!

我們可以發現,一個Reactor線程承擔了所有的網絡事件,例如監聽和響應,高并發場景下單線程存在性能問題。

為了充分利用多核能力,可以構建兩個 Reactor,主 Reactor 單獨監聽server socket,accept新連接,然后將建立的 SocketChannel 注冊給指定的從 Reactor,從Reactor再執行事件的讀寫、分發,把業務處理就扔給worker線程池完成。這就演進為 ”主從Reactor模式“ 設計模式。


所以,如果有人直接幫我們 封裝好這樣的設計模式 ,是不是太好了?

沒錯,Netty就是這樣的“活雷鋒”!

Netty就使用了主從Reactor模式封裝了Java NIO包的使用,大大提高了性能。

3.2 其他優點 (以后的核心知識點)

除了封裝了高性能的設計模式外,Netty還有許多其他優點:

穩定性。 Netty 更加可靠穩定,修復和完善了 JDK NIO 較多已知問題,包括 select 空轉導致 CPU 消耗 100%、keep-alive 檢測等問題。

性能優化。對象池復用技術。Netty 通過復用對象,避免頻繁創建和銷毀帶來的開銷。零拷貝技術。 除了操作系統級別的零拷貝技術外,Netty 提供了面向用戶態的零拷貝技術,在 I/O 讀寫時直接使用 DirectBuffer,避免了數據在堆內存和堆外內存之間的拷貝。

便捷性。 Netty 提供了很多常用的工具,例如行解碼器、長度域解碼器等。如果我們使用JDK NIO包,那么這些常用工具都需要自己進行實現。

正是因為 Netty 做到了高性能、高穩定性、高易用性,完美彌補了 Java NIO 的不足,所以在我們在網絡編程時,首選Netty,而不是自己直接使用Java NIO。

回顧一下前幾章內容,到目前為止,我們從網絡I/O模型出發,一步步了解到了Netty的網絡I/O模型。

對于I/O多路復用、Java NIO包 和 Netty 的關系也有了全面的認識。

有了這些知識基礎,我們初步了解了Netty是什么,為什么使用Netty。

后面的文章,我們將逐步展開Netty框架的核心知識點,敬請期待。

 

責任編輯:姜華 來源: 阿丸筆記
相關推薦

2021-02-10 08:09:48

Netty網絡多路復用

2023-05-08 00:06:45

Go語言機制

2011-12-08 10:51:25

JavaNIO

2021-03-17 16:53:51

IO多路

2023-08-07 08:52:03

Java多路復用機制

2020-10-13 07:51:03

五種IO模型

2025-05-08 08:01:05

2024-12-30 00:00:05

2023-11-08 09:22:14

I/ORedis阻塞

2021-06-09 19:25:13

IODubbo

2022-12-08 09:10:11

I/O模型Java

2019-12-23 14:53:26

IO復用

2022-09-12 06:33:15

Select多路復用

2022-04-13 07:59:23

IOBIONIO

2023-01-09 10:04:47

IO多路復用模型

2020-08-31 07:16:04

BIONIO多路復用器

2021-05-31 06:50:47

SelectPoll系統

2020-10-14 09:11:44

IO 多路復用實現機

2009-06-29 18:09:12

多路復用Oracle

2021-03-04 08:34:55

同步阻塞非阻塞
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品成人一区二区 | 在线观看中文字幕一区二区 | 澳门永久av免费网站 | 欧美激情视频一区二区三区免费 | 国产成人综合一区二区三区 | 国产午夜在线 | 国产盗摄视频 | 亚洲精品影院 | 欧美黄在线观看 | 欧美男人天堂 | 美女爽到呻吟久久久久 | 日日操夜夜操天天操 | 99久久婷婷国产综合精品首页 | 欧洲免费毛片 | 国产区在线 | 免费黄色录像视频 | 久久久久9999亚洲精品 | 国产一区| 日韩欧美在线视频 | 久久久久九九九女人毛片 | 人人人人干 | 伊人爽 | 亚洲精品国产第一综合99久久 | 免费激情av | 毛片久久久 | 国产一区二区电影网 | 亚洲国产高清高潮精品美女 | 色爱综合网 | 午夜二区| 亚洲一区二区三区视频 | 综合久久综合久久 | 日韩在线播放av | 中国美女av | 午夜精品三区 | 亚洲精品乱码久久久久久9色 | 成人影院网站ww555久久精品 | 欧美激情99 | 午夜影院在线观看免费 | 欧美天堂在线 | 亚洲精品一区二三区不卡 | 91在线观看|