Netty Channel 接口名詞理解

 

1.Channel
channel 是負責數據讀,寫的對象,有點相似於老的io裏面的stream,他和stream的區別,channel是雙向的
既能夠write 也能夠read,而stream要分outstream和inputstream。並且在NIO中用戶不該該直接從channel中讀寫數據,
而是應該經過buffer,經過buffer再將數據讀寫到channel中。
一個channel 能夠提供給用戶下面幾個信息
(1)channel的當前狀態,好比open 仍是closed
(2)ChannelConfig對象,表示channel的一些參數,好比bufferSize
(3)channel支持的全部i/o操做(好比read,write,connect.bind)以及ChannelPipeLine(下面解釋)html

2.ChannelConfig
channel的參數,以Map 數據結構來存儲java

3.ChannelEvent
ChannelEvent廣義的認爲Channel相關的事件,他是否分Upstream events和downstream events兩大塊,這裏須要注意的,讓是server爲
主體的話,從client的數據到server的過程是Upstream;而server到client的數據傳輸過程叫downstream;而若是以client爲主體
的話,從server到client的過程對client來講是Upstream,而client到server的過程對client來講就是downstream。
Upstream events包括:
messageReceived:信息被接受時 ---MessageEvent
exceptionCaught:產生異常時 ---ExceptionEvent
channelOpen:channel被開啓時 ---ChannelStateEvent
channelClosed:channel被關閉時 ---ChannelStateEvent
channelBound:channel被開啓並準備去鏈接但還未鏈接上的時候 ---ChannelStateEvent
channelUnbound:channel被開啓不許備去鏈接時候 ---ChannelStateEvent
channelConnected:channel被鏈接上的時候 ---ChannelStateEvent
channelDisconnected:channel鏈接斷開的時候 ---ChannelStateEvent
channelInterestChanged:Channel的interestOps被改變的時候 ------ChannelStateEvent
writeComplete:寫到遠程端完成的時候 --WriteCompletionEvent網絡

Downstream events包括:
write:發送信息給channel的時候 --MessageEvent
bind:綁定一個channel到指定的本地地址 --ChannelStateEvent
unbind:解除當前本地端口的綁定--ChannelStateEvent
connect:將channel鏈接到遠程的機 --ChannelStateEvent
disconnect:將channel與遠程的機鏈接斷開 --ChannelStateEvent
close:關閉channel --ChannelStateEvent數據結構

須要注意的是,這裏沒有open event,這是由於當一個channel被channelFactory建立的話,channel老是已經被打開了。app

此外還有兩個事件類型是當父channel存在子channel的狀況
childChannelOpen:子channel被打開 ---ChannelStateEvent
childChannelClosed:子channel被關閉 ---ChannelStateEvent異步

4.ChannelHandler
channel是負責傳送數據的載體,那麼數據確定須要根據要求進行加工處理,那麼這個時候就用到ChannelHandler
不一樣的加工能夠構建不一樣的ChannelHandler,而後放入ChannelPipeline中
此外須要有ChannelEvent觸發後才能到達ChannelHandler,所以根據event不一樣有下面兩種的sub接口ChannelUpstreamHandler
和ChannelDownstreamHandler。
一個ChannelHandler一般須要存儲一些狀態信息做爲判斷信息,經常使用作法定義一個變量
好比
public class DataServerHandler extends {@link SimpleChannelHandler} {
 *
 *     <b>private boolean loggedIn;</b>
 *
 *     {@code @Override}
 *     public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *         {@link Channel} ch = e.getChannel();
 *         Object o = e.getMessage();
 *         if (o instanceof LoginMessage) {
 *             authenticate((LoginMessage) o);
 *             <b>loggedIn = true;</b>
 *         } else (o instanceof GetDataMessage) {
 *             if (<b>loggedIn</b>) {
 *                 ch.write(fetchSecret((GetDataMessage) o));
 *             } else {
 *                 fail();
 *             }
 *         }
 *     }
 *     ...
 * }
 
 // Create a new handler instance per channel.
 * // See {@link Bootstrap#setPipelineFactory(ChannelPipelineFactory)}.
 * public class DataServerPipelineFactory implements {@link ChannelPipelineFactory} {
 *     public {@link ChannelPipeline} getPipeline() {
 *         return {@link Channels}.pipeline(<b>new DataServerHandler()</b>);
 *     }
 * }
 
除了這種,每一個ChannelHandler均可以從ChannelHandlerContext中獲取或設置數據,那麼下面的作法就是利用ChannelHandlerContext
設置變量
* {@code @Sharable}
 * public class DataServerHandler extends {@link SimpleChannelHandler} {
 *
 *     {@code @Override}
 *     public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *         {@link Channel} ch = e.getChannel();
 *         Object o = e.getMessage();
 *         if (o instanceof LoginMessage) {
 *             authenticate((LoginMessage) o);
 *             <b>ctx.setAttachment(true)</b>;
 *         } else (o instanceof GetDataMessage) {
 *             if (<b>Boolean.TRUE.equals(ctx.getAttachment())</b>) {
 *                 ch.write(fetchSecret((GetDataMessage) o));
 *             } else {
 *                 fail();
 *             }
 *         }
 *     }
 *     ...
 * }
 
 * public class DataServerPipelineFactory implements {@link ChannelPipelineFactory} {
 *
 *     private static final DataServerHandler <b>SHARED</b> = new DataServerHandler();
 *
 *     public {@link ChannelPipeline} getPipeline() {
 *         return {@link Channels}.pipeline(<b>SHARED</b>);
 *     }
 * }
 這兩種作法仍是有區別的,上面的變量作法,每一個new的handler 對象,變量是不共享的,而下面的ChannelHandlerContext是共享的
 
 若是須要不一樣的handler之間共享數據,那怎麼辦,那就用ChannelLocal
 例子:
  public final class DataServerState {
 *
 *     <b>public static final {@link ChannelLocal}&lt;Boolean&gt; loggedIn = new {@link ChannelLocal}&lt;Boolean&gt;() {
 *         protected Boolean initialValue(Channel channel) {
 *             return false;
 *         }
 *     }</b>
 *     ...
 * }
 *
 * {@code @Sharable}
 * public class DataServerHandler extends {@link SimpleChannelHandler} {
 *
 *     {@code @Override}
 *     public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *         Channel ch = e.getChannel();
 *         Object o = e.getMessage();
 *         if (o instanceof LoginMessage) {
 *             authenticate((LoginMessage) o);
 *             <b>DataServerState.loggedIn.set(ch, true);</b>
 *         } else (o instanceof GetDataMessage) {
 *             if (<b>DataServerState.loggedIn.get(ch)</b>) {
 *                 ctx.getChannel().write(fetchSecret((GetDataMessage) o));
 *             } else {
 *                 fail();
 *             }
 *         }
 *     }
 *     ...
 * }
 *
 * // Print the remote addresses of the authenticated clients:
 * {@link ChannelGroup} allClientChannels = ...;
 * for ({@link Channel} ch: allClientChannels) {
 *     if (<b>DataServerState.loggedIn.get(ch)</b>) {
 *         System.out.println(ch.getRemoteAddress());
 *     }
 * }
 * </pre>
 
5.ChannelPipeline
channelPipeline是一系列channelHandler的集合,他參照J2ee中的Intercepting Filter模式來實現的,
讓用戶徹底掌握若是在一個handler中處理事件,同時讓pipeline裏面的多個handler能夠相互交互。
Intercepting Filter:http://java.sun.com/blueprints/corej2eepatterns/Patterns/InterceptingFilter.html
對於每個channel都須要有相應的channelPipeline,當爲channel設置了channelPipeline後就不能再爲channel從新設置
channelPipeline。此外建議的作法的經過Channels 這個幫助類來生成ChannelPipeline 而不是本身去構建ChannelPipelinesocket

一般pipeLine 添加多個handler,是基於業務邏輯的
好比下面
{@link ChannelPipeline} p = {@link Channels}.pipeline();
 * p.addLast("1", new UpstreamHandlerA());
 * p.addLast("2", new UpstreamHandlerB());
 * p.addLast("3", new DownstreamHandlerA());
 * p.addLast("4", new DownstreamHandlerB());
 * p.addLast("5", new SimpleChannelHandler());
 upstream event 執行的handler按順序應該是 125
 downstream event 執行的handler按順序應該是 543
 SimpleChannelHandler 是同時實現了 ChannelUpstreamHandler和ChannelDownstreamHandler的類
上面只是具備邏輯,若是數據須要經過格式來進行編碼的話,那須要這些寫
 * {@link ChannelPipeline} pipeline = {@link Channels#pipeline() Channels.pipeline()};
 * pipeline.addLast("decoder", new MyProtocolDecoder());
 * pipeline.addLast("encoder", new MyProtocolEncoder());
 * pipeline.addLast("executor", new {@link ExecutionHandler}(new {@link OrderedMemoryAwareThreadPoolExecutor}(16, 1048576, 1048576)));
 * pipeline.addLast("handler", new MyBusinessLogicHandler());
 其中:
Protocol Decoder - 將binary轉換爲java對象
Protocol Encoder - 將java對象轉換爲binary
ExecutionHandler - applies a thread model.
Business Logic Handler - performs the actual business logic(e.g. database access)
雖然不能爲channel從新設置channelPipeline,可是channelPipeline自己是thread-safe,所以你能夠在任什麼時候候爲channelPipeline添加刪除channelHandleride

須要注意的是,下面的代碼寫法不能達到預期的效果
 * public class FirstHandler extends {@link SimpleChannelUpstreamHandler} {
 *
 *     {@code @Override}
 *     public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *         // Remove this handler from the pipeline,
 *         ctx.getPipeline().remove(this);
 *         // And let SecondHandler handle the current event.
 *         ctx.getPipeline().addLast("2nd", new SecondHandler());
 *         ctx.sendUpstream(e);
 *     }
 * }
 前提如今Pipeline只有最後一個FirstHandler,
 上面明顯是想把FirstHandler從Pipeline中移除,而後添加SecondHandler。而pipeline須要只要有一個Handler,所以若是想到到達這個效果,那麼能夠
 先添加SecondHandler,而後在移除FirstHandler。fetch

6.ChannelFactory
channel的工廠類,也就是用來生成channel的類,ChannelFactory根據指定的通訊和網絡來生成相應的channel,好比
NioServerSocketChannelFactory生成的channel是基於NIO server socket的。
當一個channel建立後,ChannelPipeline將做爲參數附屬給該channel。
對於channelFactory的關閉,須要作兩步操做
第一,關閉全部該factory產生的channel包括子channel。一般調用ChannelGroup#close()。
第二,釋放channelFactory的資源,調用releaseExternalResources()this

7.ChannelGroup
 channel的組集合,他包含一個或多個open的channel,closed channel會自動從group中移除,一個channel能夠在一個或者多個channelGroup
 若是想將一個消息廣播給多個channel,能夠利用group來實現
 好比:
{@link ChannelGroup} recipients = new {@link DefaultChannelGroup}()
recipients.add(channelA);
recipients.add(channelB);
recipients.write(ChannelBuffers.copiedBuffer("Service will shut down for maintenance in 5 minutes.",CharsetUtil.UTF_8));

當ServerChannel和非ServerChannel同時都在channelGroup中的時候,任何io請求的操做都是先在ServerChannel中執行再在其餘Channel中執行。
這個規則對關閉一個server很是適用。
 
8.ChannelFuture
在netty中,全部的io傳輸都是異步,全部那麼在傳送的時候須要數據+狀態來肯定是否所有傳送成功,而這個載體就是ChannelFuture。

9.ChannelGroupFuture
針對一次ChannelGroup異步操做的結果,他和ChannelFuture同樣,包括數據和狀態。不一樣的是他由channelGroup裏面channel的全部channelFuture
組成。

10.ChannelGroupFutureListener
針對ChannelGroupFuture的監聽器,一樣建議使用ChannelGroupFutureListener而不是await();

11.ChannelFutureListener
ChannelFuture監聽器,監聽channelFuture的結果。

12.ChannelFutureProgressListener
監聽ChannelFuture處理過程,好比一個大文件的傳送。而ChannelFutureListener只監聽ChannelFuture完成未完成

13.ChannelHandlerContext
如何讓handler和他的pipeLine以及pipeLine中的其餘handler交換,那麼就要用到ChannelHandlerContext,
ChannelHandler能夠經過ChannelHandlerContext的sendXXXstream(ChannelEvent)將event傳給最近的handler
能夠經過ChannelHandlerContext的getPipeline來獲得Pipeline,並修改他,ChannelHandlerContext還能夠存放一下狀態信息attments。
一個ChannelHandler實例能夠有一個或者多個ChannelHandlerContext

14.ChannelPipelineFactory
產生ChannelPipe的工廠類

15.ChannelState 記載channel狀態常量

相關文章
相關標籤/搜索