網路程式設計-Netty-Reactor模型
阿新 • • 發佈:2020-06-09
[toc]
---
- Posted by [微博@Yangsc_o](https://img-blog.csdnimg.cn/20200515112607757.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lhbmcxOTg5MDc=,size_16,color_FFFFFF,t_70)
- 原創文章,版權宣告:自由轉載-非商用-非衍生-保持署名 | [Creative Commons BY-NC-ND 3.0](http://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh)
---
# # 摘要
在前兩篇《快速理解Linux網路I_O》、《java的I_O模型-BIO&NIO&AIO》兩邊中介紹了Linux下的I/O模型和java中的I/O模型,今天我們介紹Reactor模型,並探究Netty的實現
# 高效能伺服器
在網際網路時代,我們使用的軟體基本上全是C/S架構,C/S架構的軟體一個明顯的好處就是:只要有網路,你可以在任何地方幹同一件事。C/S架構可以抽象為如下模型:
![image-20200608122739089](https://gitee.com/yangsanchao/images/raw/master/blogs/image-20200608122739089.png)
- C就是Client(客戶端),上面的B是Browser(瀏覽器)
- S就是Server(伺服器):**伺服器管理某種資源,並且通過操作這種資源來為它的客戶端提供某種服務**
那伺服器如何能快速的處理使用者的請求呢?在我看來高效能伺服器至少要滿足如下幾個需求:
- 效率高:既然是高效能,那處理客戶端請求的效率當然要很高了
- 高可用:不能隨便就掛掉了
- 程式設計簡單:基於此伺服器進行業務開發需要足夠簡單
- 可擴充套件:可方便的擴充套件功能
- 可伸縮:可簡單的通過部署的方式進行容量的伸縮,也就是服務需要無狀態
而滿足如上需求的一個基礎就是高效能的IO!
# Reactor模式
什麼是Reactor模式?
兩種I/O多路複用模式:Reactor和Proactor,兩個與事件分離器有關的模式是Reactor和Proactor。Reactor模式採用同步IO,而Proactor採用非同步IO。
在Reactor中,事件分離器負責等待檔案描述符或socket為讀寫操作準備就緒,然後將就緒事件傳遞給對應的處理器,最後由處理器負責完成實際的讀寫工作。
在Proactor模式中,處理器--或者兼任處理器的事件分離器,只負責發起非同步讀寫操作。IO操作本身由作業系統來完成。傳遞給作業系統的引數需要包括使用者定義的資料緩衝區地址和資料大小,作業系統才能從中得到寫出操作所需資料,或寫入從socket讀到的資料。事件分離器捕獲IO操作完成事件,然後將事件傳遞給對應處理器。
說人話的方式理解:
- reactor:能收了你跟俺說一聲。
- proactor: 你給我收十個位元組,收好了跟俺說一聲。
Doug Lea是這樣類比的
- Reactor通過排程適當的處理程式來響應IO事件;
- 處理程式執行非阻塞操作
- 通過將處理程式繫結到事件來管理;
![image-20200608173303651](https://gitee.com/yangsanchao/images/raw/master/blogs/image-20200608173303651.png)
## Reactor單執行緒模型設計
![image-20200608175038780](https://gitee.com/yangsanchao/images/raw/master/blogs/image-20200608175038780.png)
單執行緒版本Java NIO的支援:
- Channels:與支援非阻塞讀取的檔案,套接字等的連線
- Buffers:類似於陣列的物件,可由Channels直接讀取或寫入
- Selectors:通知一組通道中哪一個有IO事件
- SelectionKeys:維護IO事件狀態和繫結
- Reactor 程式碼如下
```java
public class Reactor implements Runnable {
final Selector selector;
final ServerSocketChannel serverSocketChannel;
public Reactor(int port) throws IOException {
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(port));
serverSocketChannel.configureBlocking(false);
SelectionKey key = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
key.attach(new Acceptor());
}
@Override
public void run() {
while (!Thread.interrupted()) {
try {
selector.select();