說說我用netty的經驗和教訓

pelp1451 8年前發布 | 56K 次閱讀 Netty 網絡工具包

簡單梳理圖中的紅線過程

  1. 客戶端連接
  2. boss channel接受連接,創建或者找到client channel,并且將處理過程delegate到child handlers
  3. 所謂delegate到child handlers,意思是child Eventloop會用這個channel的handlers來進行業務邏輯處理
  4. 事件是netty用來通知的方式,如果client的通道上有事件發生,比如通道上有數據了,那么netty會觸發channelRead方法;如果handler在處理過程拋了異常,那么netty會觸發exceptionCaught()方法執行
  5. 調用write方法往通道上發送數據

ServerBootStrap

  • 理清ServerBootStrap要干的幾件事情
    • 2個線程池,很重。
    • channel類型指定,NioServerChannel
    • childHandler的指定
    • 一些參數的指定
    • bind
  • 為啥要干這些事情
    • 線程池是用來執行方法的
    • Handler用來執行業務邏輯
  • 注意點
    • 一般我們把整個Server的邏輯拆成2塊,1)start;2)stop;
    • start最終目的是要執行bind,并且等待bind成功,所以一般我們會在ChannelFuture上加上sync()方法進行同步等待。
    • stop最終要釋放所有的資源,主要是2個線程池,close所有的child channels和boss channel
    • 可以用 Runtime.getRuntime().addShutdownHook(new ShutdownThread(this)); 結束server,注意ShutdownHook接收的是15信號,所以優雅關閉的命令是 kill -15 pid

EventLoop

  • Eventloop就是一個運行時的載體,它會執行每個channel上的handlers
  • Eventloop擴展自 ScheduledExecutorService ,對于在Chile通道上執行一些定時任務很合適
  • inEventLoop()方法可以用來判斷是否當前線程可以馬上執行,如果true,那就直接do();如果false,那就 executors().schedule(new Runnable(){do();}, delayTime)
  • 在做代理的時候,new BootStrap().group()應該要復用當前channel.eventloop(),這樣效率是最高的

Channel & ChannelContext

  • 每個連接用一個Channel來抽象,有10w個連接那么就有10w個Channel實體,并且每個Channel有一個對應的context
  • 上面這句話的意思是,Channel和ChannelContext都是線程安全的,因為每個通道一份,你不會在不同的通道上還要共享啥東西吧。。。
  • channel.write()會導致從最后一個outboundhandler開始往前write;ctx.write()會從當前這個outboundhandler開始往前write,所以如果你在inboundhandler里面write,那么效果和channel.write()是一樣的

Handler & Pipeline

  • 我一開始一直理解錯了,以為內存中只有一份Handlers和Pipeline;其實不是,每個Channel都有一份自己的Handlers和Pipeline。這樣就可以理解為啥在netty中不需要去處理共享資源了,因為每次Eventloop都是去拿到一個channel,及其handlers,pipeline。然后你在業務邏輯中也不用去考慮鎖之類的東西,因為每個通道都是獨立的。
  • 每個inboundhandler都有如下方法需要實現
    • void channelRegistered(ChannelHandlerContext ctx) throws Exception;
    • void channelUnregistered(ChannelHandlerContext ctx) throws Exception;
    • void channelActive(ChannelHandlerContext ctx) throws Exception;
    • void channelInactive(ChannelHandlerContext ctx) throws Exception;
    • void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;
    • void channelReadComplete(ChannelHandlerContext ctx) throws Exception;
    • void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;
    • void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception;
    • void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
  • 每個outboundHandler有如下方法需要實現
    • void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception;
    • `void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception;
    • void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;
    • void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;
    • void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;
    • void read(ChannelHandlerContext ctx) throws Exception;
    • void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception;
    • void flush(ChannelHandlerContext ctx) throws Exception;
  • 我為啥滔滔不絕寫上面那么多?肯定不是蛋疼,對不對。我是要告訴你,你在用別人的handler的時候,千萬記住這些方法肯定都實現了,你沒看到的話,去超類里面找!
  • 你沒看到 channelRead() 方法?快去父類里面找,不然你怎么知道整個的邏輯是怎么處理的?decode()其實是包含在channelread()方法中的
  • 你只需要關注某些已經實現的Codec類的部分方法?握草,不知道整個的邏輯是怎么處理的你怎么會用?
  • 并且!!!!channel上產生事件以后,每個handler中的對應方法都會走到的,為什么?因為默認的adaptor里面用的處理方法是ctx.fireXXX()這樣就把時間傳遞到下一個handler去處理了,并且肯定會調用下一個handler中的channelXXX()

 

來自:https://blog.huachao.me/2016/7/說說我用netty的經驗和教訓/

 

 本文由用戶 pelp1451 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!