說說我用netty的經驗和教訓
簡單梳理圖中的紅線過程
- 客戶端連接
- boss channel接受連接,創建或者找到client channel,并且將處理過程delegate到child handlers
- 所謂delegate到child handlers,意思是child Eventloop會用這個channel的handlers來進行業務邏輯處理
- 事件是netty用來通知的方式,如果client的通道上有事件發生,比如通道上有數據了,那么netty會觸發channelRead方法;如果handler在處理過程拋了異常,那么netty會觸發exceptionCaught()方法執行
- 調用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 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!