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