Netty系列入門之HelloWorld(一)編程
一. 簡介promise
Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server.服務器
'Quick and easy' doesn't mean that a resulting application will suffer from a maintainability or a performance issue. Netty has been designed carefully with the experiences earned from the implementation of a lot of protocols such as FTP, SMTP, HTTP, and various binary and text-based legacy protocols. As a result, Netty has succeeded to find a way to achieve ease of development, performance, stability, and flexibility without a compromise.網絡
上面一段話引子Netty官網:Netty是一個基於NIO的客戶端與服務端框架,可讓咱們簡單快速的開發協議化的客戶端/服務端的網絡應用。Netty能夠很是簡單的進行網絡編程,例如TCP和UDP的套接字服務。"快速和簡單"並不意味着咱們使用Netty編寫的應用很難維護,也不會致使性能問題。Netty的設計很是的謹慎,設計Netty的經驗來源於對FTP, SMTP,HTTP以及遺留的各類二進制和基於文本的協議的大量的實現。總之,Netty在實現了快速快發,高性能,穩定性強,易於擴展方面尋找到一種極佳的方式,而不會爲了某些因素做出任何的妥協。app
固然,以上只是官網的陳述,筆者發現幾乎全部的框架都會使用"簡單"、"易於使用"這類的詞語,然而筆者在學習Netty的過程當中並不這麼認爲,多是筆者智商有限吧。那麼多的不說了,按照筆者一向的風格,咱們就直接上代碼吧。框架
二. Netty入門之HelloWorldsocket
對於Netty來講,編寫一個"Hello World"程序並非那麼的簡單,對於初學Netty的人來說,可能以爲異常的繁瑣,怎麼說了,繁瑣也得學呀,誰讓咱走上了編程這條不歸路呢?ide
2.1 Netty的啓動服務程序函數
public class ServerTest { public static void main(String[] args) throws InterruptedException { /** * bossGroup, 父類的事件循環組只是負責鏈接,獲取到鏈接後交給 workergroup子的事件循環組, * 參數的獲取,業務的處理等工做均是由workergroup這個子事件循環組來完成,一個事件循環組同樣 * 能夠完成全部的工做,可是Netty推薦的方式是使用兩個事件循環組。 */ EventLoopGroup bossGroup = new NioEventLoopGroup(); //建立父事件循環組 EventLoopGroup workerGroup = new NioEventLoopGroup(); //建立子類的事件循環組 try{ //建立啓動服務器的對象 ServerBootstrap serverBootstrap = new ServerBootstrap(); /** * group方法接收兩個參數, 第一個爲父時間循環組,第二個參數爲子事件循環組 */ serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) //bossGroup的通道,只是負責鏈接 .childHandler(new TestChannelnitializer()); //workerGroup的處理器, ChannelFuture channelFuture = serverBootstrap.bind(8899).sync(); //綁定端口 channelFuture.channel().closeFuture().sync(); }finally{ bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
2.2 通道初始化程序oop
通道的初始化程序主要是爲workerGroup添加各類Handler.
/** * 初始化一個通道,主要用於設置各類Handler */ public class TestChannelnitializer extends ChannelInitializer<SocketChannel>{ @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); /** * Handler就至關於Servlet中的過濾器, 請求和響應都會走Handler * HttpServerCodec: http的編解碼器,用於Http請求和相應 */ pipeline.addLast("httpServerCodec", new HttpServerCodec()); pipeline.addLast("testHttpServerHandler", new TestHttpServerHandler()); } }
2.3 自定義的Handler
/** * 自定義處理器 */ public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject>{ @Override protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { if(msg instanceof HttpRequest){ //要返回的內容, Channel能夠理解爲鏈接,而鏈接中傳輸的信息要爲ByteBuf ByteBuf content = Unpooled.copiedBuffer("Hello World", CharsetUtil.UTF_8); //構造響應 FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content); //設置頭信息的的MIME類型 response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); //內容類型 //設置要返回的內容長度 response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes()); //內容長度 //將響應對象返回 ctx.writeAndFlush(response); } } //通道註冊成功 @Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { System.out.println("channel register..."); super.channelRegistered(ctx); } /** * 自定義的Handler被添加,也就是在TestChannelnitializer的initChannel方法中, * pipeline.addLast("testHttpServerHandler", new TestHttpServerHandler()); * 這行代碼執行的時候,該方法被觸發 */ @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { System.out.println("handler added..."); super.handlerAdded(ctx); } //通道處於活動狀態,便可用狀態 @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println("channel active..."); super.channelActive(ctx); } //通道處於不活動狀態 @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { System.out.println("channel inactive..."); super.channelInactive(ctx); } //通道取消註冊 @Override public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { System.out.println("channel unregister..."); super.channelUnregistered(ctx); } }
三.運行
首先啓動ServerTest的主函數,而後再網頁中輸入: http://localhost:88899,就會出現你但願看到的東西(前提是代碼要寫對),以下圖:
四.總結
不少人可能看到該代碼會以爲頭昏腦脹,誰不是呢?筆者對於編程的學習方式一直都是:不懂就敲,先學會用,仍是不懂,接着敲,直到敲到你認爲不少東西理所固然了,就是會了。