現在是2018年1月11日18:12分,已經是下班時間了,小Alan今天給大家簡單的介紹一下Netty,讓大家以后在使用到Netty的時候能夠有一定的了解和基礎,這樣深入學習Netty以及以后靈活應用這門技術也就不在話下了,萬丈高樓平地起,程序猿們平時還是要注重積累,多花些時間在技術上面,如果實在對代碼提不起興趣就早點規划好自己的發展路線,死磕着也沒什么必要,對自己沒啥好處,但是如果你至少不討厭編程,那么還是多多學習吧!
Netty是什么
Netty提供異步的、事件驅動的網絡應用程序框架和工具,用以快速開發高性能、高可靠性的網絡服務器和客戶端程序。
Netty的架構

Netty的特性
設計:
------統一的API,適用於不同的協議(阻塞和非阻塞)
------基於靈活、可擴展的事件驅動模型
------高度可定制的線程模型
------可靠的無連接數據Socket支持(UDP)
性能:
------更好的吞吐量,低延遲
------更省資源
------盡量減少不必要的內存拷貝
安全:
------完整的SSL/TLS和STARTTLS的支持
------能在Applet與谷歌Android的限制環境運行良好
健壯性:
------不再因過快、過慢或超負載連接導致OutOfMemoryError
------不再有在高速網絡環境下NIO讀寫頻率不一致的問題
易用:
------完善的Java doc,用戶指南和樣例
------簡潔簡單
------僅依賴於JDK1.5
Netty怎么用
小Alan教大家使用Netty3或Netty4發布Http協議服務接口,來引導大家進入Netty的世界。
Netty3實現Http協議服務接口步驟:
第一步:創建Http業務處理服務類,代碼如下
1 package com.alanlee.http; 2 3 import static org.jboss.netty.handler.codec.http.HttpResponseStatus.OK; 4 import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1; 5 6 import org.jboss.netty.buffer.ChannelBuffer; 7 import org.jboss.netty.buffer.DynamicChannelBuffer; 8 import org.jboss.netty.channel.Channel; 9 import org.jboss.netty.channel.ChannelFuture; 10 import org.jboss.netty.channel.ChannelFutureListener; 11 import org.jboss.netty.channel.ChannelHandlerContext; 12 import org.jboss.netty.channel.ExceptionEvent; 13 import org.jboss.netty.channel.MessageEvent; 14 import org.jboss.netty.channel.SimpleChannelUpstreamHandler; 15 import org.jboss.netty.handler.codec.http.DefaultHttpResponse; 16 import org.jboss.netty.handler.codec.http.HttpRequest; 17 import org.jboss.netty.handler.codec.http.HttpResponse; 18 import org.slf4j.Logger; 19 import org.slf4j.LoggerFactory; 20 21 /** 22 * HTTP服務業務處理類. 23 * 24 * @author AlanLee 25 * @version 2018/01/11 26 * 27 */ 28 public class HttpServerHandler extends SimpleChannelUpstreamHandler 29 { 30 31 /** 32 * 日志類. 33 */ 34 protected static final Logger LOGGER = LoggerFactory.getLogger(HttpServerHandler.class); 35 36 @Override 37 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception 38 { 39 40 HttpRequest request = (HttpRequest) e.getMessage(); 41 String method = request.getMethod().getName(); 42 String url = request.getUri().toLowerCase(); 43 System.out.println(method); 44 System.out.println(url); 45 46 // 接收請求內容並打印 47 ChannelBuffer buffer = request.getContent(); 48 String requestStr = new String(buffer.array(), "UTF-8"); 49 System.out.println(requestStr); 50 51 // 處理響應消息 52 HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); 53 ChannelBuffer responseBuffer = new DynamicChannelBuffer(2048); 54 responseBuffer.writeBytes("你是豬嗎?".getBytes("UTF-8")); 55 response.setContent(responseBuffer); 56 // 返回內容的MIME類型 57 response.setHeader("Content-Type", "text/html; charset=UTF-8"); 58 // 響應體的長度 59 response.setHeader("Content-Length", response.getContent().writerIndex()); 60 Channel ch = e.getChannel(); 61 62 // 響應給客戶端 63 ChannelFuture f = ch.write(response); 64 65 // 數據發送完畢,則關閉連接通道. 66 f.addListener(new ChannelFutureListener() 67 { 68 public void operationComplete(ChannelFuture future) throws Exception 69 { 70 future.getChannel().close(); 71 } 72 }); 73 } 74 75 /** 76 * 發生異常 77 */ 78 @Override 79 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) 80 { 81 LOGGER.error("exceptionCaught(): ", e.getCause()); 82 e.getCause().printStackTrace(); 83 } 84 85 }
第二步:創建Http管道類工廠用來聯結Http業務處理服務類,代碼如下
1 package com.alanlee.http; 2 3 import org.jboss.netty.channel.ChannelPipeline; 4 import org.jboss.netty.channel.ChannelPipelineFactory; 5 import org.jboss.netty.channel.Channels; 6 import org.jboss.netty.handler.codec.http.HttpRequestDecoder; 7 import org.jboss.netty.handler.codec.http.HttpResponseEncoder; 8 9 /** 10 * HTTP管道類工廠. 11 * 12 * @author AlanLee 13 * @version 2018/01/11 14 * 15 */ 16 public class ServerPipelineFactory implements ChannelPipelineFactory 17 { 18 19 /** 20 * 獲取管道. 21 * 22 * @return ChannelPipeline 管道 23 */ 24 public ChannelPipeline getPipeline() 25 { 26 ChannelPipeline pipeline = Channels.pipeline(); 27 System.out.println("initChannel pipeline"); 28 // 解碼 29 pipeline.addLast("decoder", new HttpRequestDecoder(1024, 1024, 1000 * 1024)); 30 // 編碼 31 pipeline.addLast("encoder", new HttpResponseEncoder()); 32 // 請求的業務類 33 pipeline.addLast("handler", new HttpServerHandler()); 34 return pipeline; 35 } 36 37 }
最后,讓我們利用Netty3來發布Http協議服務接口,代碼如下
1 package com.alanlee.http; 2 3 import java.net.InetSocketAddress; 4 import java.util.concurrent.Executors; 5 6 import org.jboss.netty.bootstrap.ServerBootstrap; 7 import org.jboss.netty.channel.ChannelFactory; 8 import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; 9 10 /** 11 * http服務啟動類 12 * 13 * @author AlanLee 14 * @version 2018/01/11 15 * 16 */ 17 public class HttpServer 18 { 19 20 public static void main(String[] args) 21 { 22 ChannelFactory factory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), 23 Executors.newCachedThreadPool()); 24 // 初始化channel的輔助類 25 ServerBootstrap bootstrap = new ServerBootstrap(factory); 26 bootstrap.setPipelineFactory(new ServerPipelineFactory()); 27 // 創建服務器端channel的輔助類,接收connection請求 28 bootstrap.bind(new InetSocketAddress(8080)); 29 System.out.println("Start http server success!"); 30 } 31 }
Netty4實現Http協議服務接口步驟:
第一步:創建Http業務處理服務類,代碼如下
1 package com.alanlee.netty2; 2 3 import io.netty.buffer.ByteBuf; 4 import io.netty.buffer.Unpooled; 5 import io.netty.channel.ChannelHandlerContext; 6 import io.netty.channel.SimpleChannelInboundHandler; 7 import io.netty.handler.codec.http.DefaultFullHttpResponse; 8 import io.netty.handler.codec.http.FullHttpRequest; 9 import io.netty.handler.codec.http.HttpHeaderNames; 10 import io.netty.handler.codec.http.HttpHeaderValues; 11 import io.netty.handler.codec.http.HttpHeaders; 12 import io.netty.handler.codec.http.HttpResponseStatus; 13 import io.netty.handler.codec.http.HttpVersion; 14 import io.netty.util.AsciiString; 15 16 /** 17 * HttpServer業務處理 18 * 19 * @author AlanLee 20 * @version 2018/01/11 21 * 22 */ 23 public class HttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> 24 { 25 26 private AsciiString contentType = HttpHeaderValues.TEXT_PLAIN; 27 28 @Override 29 protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception 30 { 31 String method = msg.method().name(); // 請求方式 32 String url = msg.uri().toLowerCase(); // 請求路徑 33 System.out.println(method); 34 System.out.println(url); 35 36 // 接收請求內容並打印 37 ByteBuf byteBuf = msg.content(); 38 byte[] bytes = new byte[byteBuf.readableBytes()]; 39 byteBuf.readBytes(bytes); 40 String requestStr = new String(bytes, "UTF-8"); 41 System.out.println(requestStr); 42 43 DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, 44 Unpooled.wrappedBuffer("你才是豬!".getBytes())); 45 46 HttpHeaders heads = response.headers(); 47 // 返回內容的MIME類型 48 heads.add(HttpHeaderNames.CONTENT_TYPE, contentType + "; charset=UTF-8"); 49 // 響應體的長度 50 heads.add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); 51 // 表示是否需要持久連接 52 heads.add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); 53 54 // 響應給客戶端 55 ctx.write(response); 56 } 57 58 /** 59 * 數據發送完畢,則關閉連接通道. 60 */ 61 @Override 62 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception 63 { 64 System.out.println("channelReadComplete"); 65 super.channelReadComplete(ctx); 66 ctx.flush(); 67 } 68 69 /** 70 * 發生異常 71 */ 72 @Override 73 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception 74 { 75 System.out.println("exceptionCaught"); 76 if (null != cause) 77 cause.printStackTrace(); 78 if (null != ctx) 79 ctx.close(); 80 } 81 82 }
最后,讓我們利用Netty4來發布Http協議服務接口,代碼如下
1 package com.alanlee.netty2; 2 3 import io.netty.bootstrap.ServerBootstrap; 4 import io.netty.channel.ChannelInitializer; 5 import io.netty.channel.ChannelOption; 6 import io.netty.channel.nio.NioEventLoopGroup; 7 import io.netty.channel.socket.SocketChannel; 8 import io.netty.channel.socket.nio.NioServerSocketChannel; 9 import io.netty.handler.codec.http.HttpObjectAggregator; 10 import io.netty.handler.codec.http.HttpRequestDecoder; 11 import io.netty.handler.codec.http.HttpResponseEncoder; 12 13 /** 14 * 搭建HttpServer 15 * 16 * @author Alanlee 17 * @version 2018/01/11 18 * 19 */ 20 public class HttpServer 21 { 22 23 private final int port; 24 25 public HttpServer(int port) 26 { 27 this.port = port; 28 } 29 30 public static void main(String[] args) throws InterruptedException 31 { 32 new HttpServer(8081).start(); 33 System.out.println("Start http server success!"); 34 } 35 36 public void start() throws InterruptedException 37 { 38 // 初始化channel的輔助類 39 ServerBootstrap b = new ServerBootstrap(); 40 NioEventLoopGroup group = new NioEventLoopGroup(); 41 b.group(group).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() 42 { 43 /** 44 * 初始化channel 45 */ 46 @Override 47 protected void initChannel(SocketChannel ch) throws Exception 48 { 49 System.out.println("initChannel ch:" + ch); 50 // 獲取管道 51 ch.pipeline().addLast("decoder", new HttpRequestDecoder()) // 解碼 52 .addLast("encoder", new HttpResponseEncoder()) // 編碼 53 /* aggregator,消息聚合器(重要)。 54 Netty4中為什么能有FullHttpRequest這個東西, 55 就是因為有他,HttpObjectAggregator,如果沒有他, 56 就不會有那個消息是FullHttpRequest的那段Channel, 57 同樣也不會有FullHttpResponse,HttpObjectAggregator(512 * 1024)的參數含義是消息合並的數據大小, 58 如此代表聚合的消息內容長度不超過512kb。*/ 59 .addLast("aggregator", new HttpObjectAggregator(512 * 1024)) 60 .addLast("handler", new HttpHandler()); // 請求的業務類 61 } 62 63 }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE); 64 65 // 創建服務器端channel的輔助類,接收connection請求 66 b.bind(port).sync(); 67 } 68 69 }
檢驗成果
我們可以通過運行Netty3以及Netty4對應的HttpServer中的main方法來啟動我們的Http服務器模擬。
啟動Netty3提供的Http協議服務器,結果如下:

啟動成功之后,我們利用Postman工具來做個簡單的測試,注意這里Netty3使用的是8080端口,結果如下:

控制台輸出內容如下:

我們再來啟動Netty4提供的Http協議服務器,結果如下:

啟動成功之后,我們利用Postman工具來做個簡單的測試,注意這里Netty4使用的是8081端口,結果如下:

控制台輸出內容如下:

這樣,我們就成功的使用了Netty3和Netty4發布了Http協議服務接口,是不是很類似於我們的web后端開發,在平時的工作中如果遇到需要高並發的項目往往會需要將項目拆成后台節點來開發,此時可不僅僅web端需要提供接口,后台節點也是需要提供接口的,這時Netty就正好符合需求,所以大家可以花些時間去掌握Netty,建議掌握Netty4版本,這樣版本升級的改動量會小很多,這里小Alan給大家開了扇門,把你引進門,修行在個人,如果你是一個熱愛Java開發的人,也可以私聊Alan多多交流,只要Alan空閑的時候。
結束語:時間是最公平的,活一天就擁有24小時,差別只是珍惜。你若不相信努力和時光,時光一定第一個辜負你。有夢想就立刻行動,因為現在過的每一天,都是余生中最年輕的一天。
可愛博主:AlanLee
博客地址:http://www.cnblogs.com/AlanLee
本文出自博客園,歡迎大家加入博客園。
