1. 程式人生 > >netty入門學習(5)-超時處理

netty入門學習(5)-超時處理

服務端和客戶端同時增加如下程式碼:

		Timer trigger=new HashedWheelTimer();
		final ChannelHandler timeOutHandler=new ReadTimeoutHandler(trigger,60);
//		final ChannelHandler idleStateHandler=new IdleStateHandler(trigger,60,5,0);
		
		//設定處理客戶端訊息和各種訊息事件的類(Handler)
		bootstrap.setPipelineFactory(new ChannelPipelineFactory(){
			@Override
			public ChannelPipeline getPipeline() throws Exception {
				return Channels.pipeline(timeOutHandler,new LengthFieldPrepender(2),
						new LengthFieldBasedFrameDecoder(64*1024,0,2,0,2),
						new BusinessHandler());
			}			
		});

如果設定了ReadTimeoutHandler這個Handler,且間隔60S未讀資料,則會丟擲一個ReadTimeoutException,預設情況下不會影響資料傳送。

因為NIO是非同步處理,所以客戶端得到響應可以關閉channel,但服務端並不能明確知曉何時關閉clientChannel,所以常用的策略就是捕獲超時異常(後面還有心跳機制等)共同處理 clientChannel的關閉問題。

超時也可以使用idleStateHandler,idleStateHandler提供了讀超時,寫超時,讀寫混合超時的處理策略,與ReadTimeOutHandler不同的,idleStatehandler以向後傳遞空閒事件的方式來處理超時,如果使用idleStateHandler一般配合使用IdleStateAwareChannelHandler來捕獲狀態進行處理。

		Timer trigger=new HashedWheelTimer();
		final ChannelHandler timeOutHandler=new ReadTimeoutHandler(trigger,60);
		final ChannelHandler idleStateHandler=new IdleStateHandler(trigger,60,5,0);
        // 設定一個處理服務端訊息和各種訊息事件的類(Handler)
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            @Override
            public ChannelPipeline getPipeline() throws Exception {
                return Channels.pipeline(timeOutHandler,
                		idleStateHandler,
                		new SocketLinkState(),
                		new LengthFieldPrepender(2),
                		new LengthFieldBasedFrameDecoder(64*1024,0,2,0,2),
                		new RequestHandler());
            }
        });

	private static class SocketLinkState extends IdleStateAwareChannelHandler{
		  @Override
		  public void exceptionCaught(ChannelHandlerContext ctx,ExceptionEvent e) throws Exception{
		    // JavaUtil.callLevels();
		    Throwable throwed=e.getCause();
		    throwed.printStackTrace();
		    // throwed.printStackTrace(System.err);
		    if(throwed instanceof ReadTimeoutException){
		      ctx.getChannel().close();
		    }
		    else if(throwed instanceof IOException){
		      ctx.getChannel().close();
		    }
		    else{
		      super.exceptionCaught(ctx,e);
		    }
		  }
		  
		  @Override
		  public void channelIdle(//
		  ChannelHandlerContext ctx,//
		  IdleStateEvent e) throws Exception{

		    super.channelIdle(ctx,e);

		    Channel channel=e.getChannel();

		    switch(e.getState()){
		      case READER_IDLE: {// 讀取時間超時
		        // e.getChannel().close();// 關閉網路連線

		        // new RuntimeException().printStackTrace();
		        break;
		      }
		      case WRITER_IDLE: {// 讀取時間超時
		        SocketHeartBeat.sendHeartBeat(channel);
		        break;
		      }
		    }
		  }
	}

ReadTimeOutHandler的作用是讀超時時向後傳遞異常

idleStatehandler的作用是讀超時或寫超時向後傳遞空閒事件

SocketLinkState是對ReadTimeOutHandler和idleStatehandler進行處理,對ReadTimeOutHandler丟擲的異常在exceptionCaught中進行處理,並關閉channel,channelIdle則是捕獲住相關事件進行處理,在本例中,未對讀超時進行處理,因為在ReadTimeOutHandler已經進行處理了。針對寫超時,採用心跳機制喚醒。

心跳機制在下節中討論。