Netty框架入门
一、概述
? ??Netty是由JBOSS提供的一個java開源框架。
????Netty提供異步的、事件驅動的網絡應用程序框架和工具,用以快速開發高性能、高可靠性的網絡服務器和客戶端程序。
?
二、體系結構圖
?
三、Netty的核心結構
????Netty是典型的Reactor模型結構,在實現上,Netty中的Boss類充當mainReactor,NioWorker類充當subReactor(默認NioWorker的個數是當前服務器的可用核數)。
????在處理新來的請求時,NioWorker讀完已收到的數據到ChannelBuffer中,之后觸發ChannelPipeline中的ChannelHandler流。
????Netty是事件驅動的,可以通過ChannelHandler鏈來控制執行流向。因為ChannelHandler鏈的執行過程是在subReactor中同步的,所以如果業務處理handler耗時長,將嚴重影響可支持的并發數。
?
四、客戶端和服務器端通信Demo
????Server-main:
| ChannelFactory factory = new?NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); ServerBootstrap bootstrap = new?ServerBootstrap(factory); bootstrap.setPipelineFactory(new?ChannelPipelineFactory(){? ????@Override ????public?ChannelPipeline getPipeline() throws Exception { ????????return?Channels.pipeline(new?TimeServerHandler()); ????} }); bootstrap.setOption("child.tcpNoDelay", true); bootstrap.setOption("child.keepAlive", true); bootstrap.bind(new?InetSocketAddress(1989)); |
????ChannelFactory 是一個創建和管理Channel通道及其相關資源的工廠接口,它處理所有的I/O請求并產生相應的I/O ChannelEvent通道事件。這個工廠并自己不負責創建I/O線程。應當在其構造器中指定該工廠使用的線程池,這樣我們可以獲得更高的控制力來管理應用環境中使用的線程。
????ServerBootstrap 是一個設置服務的幫助類。設置了一個繼承自ChannelPipelineFactory的匿名類,用來作為ChannelPipeline通道,當服務器接收到一個新的連接,一個新的ChannelPipeline管道對象將被創建,并且所有在這里添加的ChannelHandler對象將被添加至這個新的ChannelPipeline管道對象。
????Server-Handler:
| @Override public?void?channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws?Exception { ????//TimeServer??? ????Channel ch = e.getChannel(); ????ChannelBuffer time = ChannelBuffers.buffer(8); ????time.writeLong(System.currentTimeMillis()); ????ChannelFuture future = ch.write(time);? ????future.addListener(new?ChannelFutureListener() {??????? ????????@Override?????? ????????public?void?operationComplete(ChannelFuture arg0) throws?Exception {??????? ????????????Channel ch = arg0.getChannel(); ????????????ch.close(); ????????} ????}); } |
????Handler中是我們的業務邏輯,在Server的Handler里重載了channelConnected方法,當收到連接請求時,將當前服務器時間寫入到Channel,并且在寫完后觸發關閉Channel。
????Client-main:
| ChannelFactory factory = new?NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); ClientBootstrap bootstrap = new?ClientBootstrap(factory); bootstrap.setPipelineFactory(new?ChannelPipelineFactory() { ????@Override?? ????public?ChannelPipeline getPipeline() throws?Exception { ????????return?Channels.pipeline(new?TimeClientHandler()); ????} }); bootstrap.setOption("tcpNoDelay",true); bootstrap.setOption("keepAlive", true); bootstrap.connect(new?InetSocketAddress("127.0.0.1", 1989)); |
????Client端初始化Netty的過程和Server類似,只是將使用到的類替換為Client端的。
????Client-Handler:
| @Override public?void?messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws?Exception { ????ChannelBuffer buf = (ChannelBuffer)e.getMessage(); ????Long currentTimeMillis = buf.readLong(); ????System.out.println(new?Date(currentTimeMillis)); ????e.getChannel().close(); } |
????Client端的Handler里,我們將從服務器端接收到的信息轉換為時間打印到控制臺。
?
五、基于HTTP協議的服務器端實現
| //HttpServerPipelineFactory.java public?class?HttpServerPipelineFactory implements?ChannelPipelineFactory { ????@Override ????public?ChannelPipeline getPipeline() throws?Exception { ????????ChannelPipeline pipeline = Channels.pipeline(); ????????pipeline.addLast("decoder", new?HttpRequestDecoder()); ????????pipeline.addLast("encoder", new?HttpResponseEncoder()); ????????pipeline.addLast("handler", new?HttpServerHandler()); ????????return?pipeline; ????} } |
????新建一個HttpServerPipelineFactory類,在getPipeline()方法中添加了對Http協議的支持。
| // HttpServer.java bootstrap.setPipelineFactory(new?HttpServerPipelineFactory()); |
????在Server里面使用我們新建的HttpServerPipelineFactory。
| //HttpServerHandler.java public?void?messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws?Exception { ????DefaultHttpRequest defaultHttpRequest = (DefaultHttpRequest)e.getMessage(); ????String uri = defaultHttpRequest.getUri(); ????byte[] data = defaultHttpRequest.getContent().array(); ????String content = URLDecoder.decode(new?String(data),"utf-8").trim(); ????System.out.println(uri+"|"+content); ????Channel ch = e.getChannel(); ????HttpResponse response = new?DefaultHttpResponse(HTTP_1_1, OK); ????ChannelBuffer buffer = new?DynamicChannelBuffer(2048); ????buffer.writeBytes("200".getBytes("UTF-8")); ????response.setContent(buffer); ????response.setHeader("Content-Type", "text/html;charset=UTF-8"); ????response.setHeader("Content-Length", response.getContent().writerIndex()); ????if?(ch.isOpen() && ch.isWritable()) {?? ????????ChannelFuture future = ch.write(response);? ????????future.addListener(new?ChannelFutureListener() {??????? ????????????@Override?????? ????????????public?void?operationComplete(ChannelFuture arg0) throws?Exception {??????????? ????????????????Channel ch = arg0.getChannel();???????? ????????????????ch.close(); ????????????}?? ????????}); ????} } |
????在Handler里面我們可以直接拿到DefaultHttpRequest類型的對象,因為Netty已經用HttpRequestDecoder幫我們把接受到的數據都轉換為HttpRequest類型了。
????使用了多個Handler后,通過下圖,Netty的事件驅動就可以被很好的理解了:
????UpstreamEvent是被UpstreamHandler們自底向上逐個處理,DownstreamEvent是被DownstreamHandler們自頂向下逐個處理,這里的上下關系就是向ChannelPipeline里添加Handler的先后順序關系。
?
六、總結
????Netty是一個簡單卻不失強大的架構。這個架構由三部分組成——緩沖(Buffer)、通道(Channel)、事件模型(Event Model)——所有的高級特性都構建在這三個核心組件之上。
?
七、深入學習
????http://netty.io/
????https://github.com/netty/netty
from:?https://www.cnblogs.com/baronzhao/p/netty_1.html
總結
- 上一篇: Netty原理和使用
- 下一篇: Netty入门官方例子