Netty 簡單樣例分析

Netty 是JBoss旗下的io傳輸的框架,他利用java裏面的nio來實現高效,穩定的io傳輸。java

做爲io傳輸,就會有client和server,下面咱們看看用netty怎樣寫client和serverbootstrap

Client:
須要作的事情:
1.配置client啓動類
  ClientBootstrap bootstrap = new ClientBootstrap(..)框架

2.根據不一樣的協議或者模式爲client啓動類設置pipelineFactory。
這裏telnet pipline Factory 在netty中已經存在,全部直接用
  bootstrap.setPipelineFactory(new TelnetClientPipelineFactory());
 也能夠本身定義
 bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() throws Exception {
                return Channels.pipeline(
                        new DiscardClientHandler(firstMessageSize));
            }
        });       
 這裏DiscardClientHandler 就是本身定義的handler,他須要
 public class DiscardServerHandler extends SimpleChannelUpstreamHandler
 繼承SimpleChannelUpstreamHandler  來實現本身的handler。這裏DiscardClientHandler
 是處理本身的client端的channel,他的
 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
        // Server is supposed to send nothing.  Therefore, do nothing.
    }
  能夠看到Discard client不須要接受任何信息
 
3.鏈接server
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));異步

這裏解釋一下channelFuture:ide

在Netty中全部的io操做都是異步的,這也就是意味任何io訪問,那麼就當即返回處理,而且不能確保
返回的數據所有完成。所以就出現了channelFuture,channelFuture在傳輸數據時候包括數據和狀態兩個
部分。他只有Uncompleted和Completedpost

 
 *                                      +---------------------------+
 *                                      | Completed successfully    |
 *                                      +---------------------------+
 *                                 +---->      isDone() = <b>true</b>      |
 * +--------------------------+    |    |   isSuccess() = <b>true</b>      |
 * |        Uncompleted       |    |    +===========================+
 * +--------------------------+    |    | Completed with failure    |
 * |      isDone() = <b>false</b>    |    |    +---------------------------+
 * |   isSuccess() = false    |----+---->   isDone() = <b>true</b>         |
 * | isCancelled() = false    |    |    | getCause() = <b>non-null</b>     |
 * |    getCause() = null     |    |    +===========================+
 * +--------------------------+    |    | Completed by cancellation |
 *                                 |    +---------------------------+
 *                                 +---->      isDone() = <b>true</b>      |
 *                                      | isCancelled() = <b>true</b>      |
 *                                      +---------------------------+
 
 既然netty io是異步的,那麼如何知道channel傳送完成有兩種方式,一種添加監聽器
 addListener(ChannelFutureListener) 還有一種直接調用await()方法,這兩種方式
 有下面的區別
 監聽器:是以事件模式的,所以代碼就須要用事件模式的樣式去寫,至關複雜,但他是non-blocking模式的
 性能方面要比await方法好,並且不會產生死鎖狀況
 
 await(): 直接方法調用,使用簡單,可是他是blocking模式,性能方面要弱並且會產生死鎖狀況
 
 不要在ChannelHandler 裏面調用await(),這是由於一般在channelHandler裏的event method是被i/o線程調用的
 (除非ChannelPipeline裏面有個ExecutionHandler),那麼若是這個時候用await就容易產生死鎖。
 
 錯誤樣例:
 // BAD - NEVER DO THIS
 * {@code @Override}
 * public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *     if (e.getMessage() instanceof GoodByeMessage) {
 *         {@link ChannelFuture} future = e.getChannel().close();
 *         future.awaitUninterruptibly();
 *         // Perform post-closure operation
 *         // ...
 *     }
 * }
 *
 正確樣例:
 * // GOOD
 * {@code @Override}
 * public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *     if (e.getMessage() instanceof GoodByeMessage) {
 *         {@link ChannelFuture} future = e.getChannel().close();
 *         future.addListener(new {@link ChannelFutureListener}() {
 *             public void operationComplete({@link ChannelFuture} future) {
 *                 // Perform post-closure operation
 *                 // ...
 *             }
 *         });
 *     }
 * }
 
 雖然await調用比較危險,可是你確保不是在一個i/o 線程中調用該方法,畢竟await方法仍是很簡潔方便的,若是
 調用該方法是在一個i/o 線程,那麼就會拋出 IllegalStateException
 
 await的timeout和i/o timeout區別
 須要注意的是這兩個timeout是不同的, #await(long),#await(long, TimeUnit), #awaitUninterruptibly(long),
 #awaitUninterruptibly(long, TimeUnit) 這裏面的timeout也i/o timeout 沒有任何關係,若是io timeout,那麼
 channelFuture 將被標記爲completed with failure,而await的timeout 與future徹底沒有關係,只是await動做的
 timeout。
 錯誤代碼
  * // BAD - NEVER DO THIS
 * {@link ClientBootstrap} b = ...;
 * {@link ChannelFuture} f = b.connect(...);
 * f.awaitUninterruptibly(10, TimeUnit.SECONDS);
 * if (f.isCancelled()) {
 *     // Connection attempt cancelled by user
 * } else if (!f.isSuccess()) {
 *     // You might get a NullPointerException here because the future
 *     // might not be completed yet.
 *     f.getCause().printStackTrace();
 * } else {
 *     // Connection established successfully
 * }
 *
 正確代碼
 * // GOOD
 * {@link ClientBootstrap} b = ...;
 * // Configure the connect timeout option.
 * <b>b.setOption("connectTimeoutMillis", 10000);</b>
 * {@link ChannelFuture} f = b.connect(...);
 * f.awaitUninterruptibly();
 *
 * // Now we are sure the future is completed.
 * assert f.isDone();
 *
 * if (f.isCancelled()) {
 *     // Connection attempt cancelled by user
 * } else if (!f.isSuccess()) {
 *     f.getCause().printStackTrace();
 * } else {
 *     // Connection established successfully
 * }
 
4.等待或監聽數據所有完成
如: future.getChannel().getCloseFuture().awaitUninterruptibly();性能

5.釋放鏈接等資源
 bootstrap.releaseExternalResources();
 
Server:
1.配置server線程

ServerBootstrap bootstrap = new ServerBootstrap(
                new NioServerSocketChannelFactory(
                        Executors.newCachedThreadPool(),
                        Executors.newCachedThreadPool()));
                       
2.設置pipeFactory
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() throws Exception {
                return Channels.pipeline(new EchoServerHandler());
            }
        });
    或者
   bootstrap.setPipelineFactory(new HttpServerPipelineFactory());
  
3.綁定sever端端口
bootstrap.bind(new InetSocketAddress(8080));netty

相關文章
相關標籤/搜索