1. 程式人生 > >netty(一) netty有哪幾部分構成

netty(一) netty有哪幾部分構成

nbsp tro sock 說明 .com 日誌 內部使用 阻塞 opera

netty

netty是一個支持高並發的非阻塞I/O框架。

Channel

Channel 是 NIO 基本的結構。它代表了一個用於連接到實體如硬件設備、文件、網絡套接字或程序組件,能夠執行一個或多個不同的 I/O 操作(例如讀或寫)的開放連接。

現在,把 Channel 想象成一個可以“打開”或“關閉”,“連接”或“斷開”和作為傳入和傳出數據的運輸工具。

Callback (回調)

callback (回調)是一個簡單的方法,提供給另一種方法作為引用,這樣後者就可以在某個合適的時間調用前者。這種技術被廣泛使用在各種編程的情況下,最常見的方法之一通知給其他人操作已完成。

Netty 內部使用回調處理事件時。一旦這樣的回調被觸發,事件可以由接口 ChannelHandler 的實現來處理。如下面的代碼,一旦一個新的連接建立了,調用 channelActive(),並將打印一條消息。

Listing 1.2 ChannelHandler triggered by a callback

public class ConnectHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {   //1
        System.out.println(
                "Client " + ctx.channel().remoteAddress() + " connected");
    }
}

1.當建立一個新的連接時調用 ChannelActive()

Future

Future 提供了另外一種通知應用操作已經完成的方式。這個對象作為一個異步操作結果的占位符,它將在將來的某個時候完成並提供結果。

JDK 附帶接口 java.util.concurrent.Future ,但所提供的實現只允許您手動檢查操作是否完成或阻塞了。這是很麻煩的,所以 Netty 提供自己了的實現,ChannelFuture,用於在執行異步操作時使用。

ChannelFuture 提供多個附件方法來允許一個或者多個 ChannelFutureListener 實例。這個回調方法 operationComplete() 會在操作完成時調用。事件監聽者能夠確認這個操作是否成功或者是錯誤。如果是後者,我們可以檢索到產生的 Throwable。簡而言之, ChannelFutureListener 提供的通知機制不需要手動檢查操作是否完成的。

每個 Netty 的 outbound I/O 操作都會返回一個 ChannelFuture;這樣就不會阻塞。這就是 Netty 所謂的“自底向上的異步和事件驅動”。

下面例子簡單的演示了作為 I/O 操作的一部分 ChannelFuture 的返回。當調用 connect() 將會直接是非阻塞的,並且調用在背後完成。由於線程是非阻塞的,所以無需等待操作完成,而可以去幹其他事,因此這令資源利用更高效。

Listing 1.3 Callback in action

Channel channel = ...;
//不會阻塞
ChannelFuture future = channel.connect(
    new InetSocketAddress("192.168.0.1", 25));

1.異步連接到遠程地址

下面代碼描述了如何利用 ChannelFutureListener 。首先,連接到遠程地址。接著,通過 ChannelFuture 調用 connect() 來 註冊一個新ChannelFutureListener。當監聽器被通知連接完成,我們檢查狀態。如果是成功,就寫數據到 Channel,否則我們檢索 ChannelFuture 中的Throwable。

註意,錯誤的處理取決於你的項目。當然,特定的錯誤是需要加以約束 的。例如,在連接失敗的情況下你可以嘗試連接到另一個。

Listing 1.4 Callback in action

Channel channel = ...;
//不會阻塞
ChannelFuture future = channel.connect(            //1
        new InetSocketAddress("192.168.0.1", 25));
future.addListener(new ChannelFutureListener() {  //2
@Override
public void operationComplete(ChannelFuture future) {
    if (future.isSuccess()) {                    //3
        ByteBuf buffer = Unpooled.copiedBuffer(
                "Hello", Charset.defaultCharset()); //4
        ChannelFuture wf = future.channel().writeAndFlush(buffer);                //5
        // ...
    } else {
        Throwable cause = future.cause();        //6
        cause.printStackTrace();
    }
}
});

1.異步連接到遠程對等節點。調用立即返回並提供 ChannelFuture。

2.操作完成後通知註冊一個 ChannelFutureListener 。

3.當 operationComplete() 調用時檢查操作的狀態。

4.如果成功就創建一個 ByteBuf 來保存數據。

5.異步發送數據到遠程。再次返回ChannelFuture。

6.如果有一個錯誤則拋出 Throwable,描述錯誤原因。

Event 和 Handler

Netty 使用不同的事件來通知我們更改的狀態或操作的狀態。這使我們能夠根據發生的事件觸發適當的行為。

這些行為可能包括:

  • 日誌
  • 數據轉換
  • 流控制
  • 應用程序邏輯

由於 Netty 是一個網絡框架,事件很清晰的跟入站或出站數據流相關。因為一些事件可能觸發傳入的數據或狀態的變化包括:

  • 活動或非活動連接
  • 數據的讀取
  • 用戶事件
  • 錯誤

出站事件是由於在未來操作將觸發一個動作。這些包括:

  • 打開或關閉一個連接到遠程
  • 寫或沖刷數據到 socket

每個事件都可以分配給用戶實現處理程序類的方法。這說明了事件驅動的範例可直接轉換為應用程序構建塊。

圖1.3顯示了一個事件可以由一連串的事件處理器來處理

Figure 1.3 Event Flow

技術分享圖片

Netty 的 ChannelHandler 是各種處理程序的基本抽象。想象下,每個處理器實例就是一個回調,用於執行對各種事件的響應。

在此基礎之上,Netty 也提供了一組豐富的預定義的處理程序,您可以開箱即用。比如,各種協議的編解碼器包括 HTTP 和 SSL/TLS。在內部,ChannelHandler 使用事件和 future 本身,創建具有 Netty 特性抽象的消費者。

整合

FUTURE, CALLBACK 和 HANDLER

Netty 的異步編程模型是建立在 future 和 callback 的概念上的。所有這些元素的協同為自己的設計提供了強大的力量。

攔截操作和轉換入站或出站數據只需要您提供回調或利用 future 操作返回的。這使得鏈操作簡單、高效,促進編寫可重用的、通用的代碼。一個 Netty 的設計的主要目標是促進“關註點分離”:你的業務邏輯從網絡基礎設施應用程序中分離。

SELECTOR, EVENT 和 EVENT LOOP

Netty 通過觸發事件從應用程序中抽象出 Selector,從而避免手寫調度代碼。EventLoop 分配給每個 Channel 來處理所有的事件,包括

  • 註冊感興趣的事件
  • 調度事件到 ChannelHandler
  • 安排進一步行動

該 EventLoop 本身是由只有一個線程驅動,它給一個 Channel 處理所有的 I/O 事件,並且在 EventLoop 的生命周期內不會改變。這個簡單而強大的線程模型消除你可能對你的 ChannelHandler 同步的任何關註,這樣你就可以專註於提供正確的回調邏輯來執行。該 API 是簡單和緊湊。

netty(一) netty有哪幾部分構成