netty入門學習(5)-超時處理
阿新 • • 發佈:2019-02-03
服務端和客戶端同時增加如下程式碼:
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已經進行處理了。針對寫超時,採用心跳機制喚醒。
心跳機制在下節中討論。