Netty是一個(gè)異步事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用程序框架,用于快速開(kāi)發(fā)可維護(hù)的高性能服務(wù)器和客戶端。它是一個(gè)NIO客戶機(jī)服務(wù)器框架,支持快速、簡(jiǎn)單地開(kāi)發(fā)網(wǎng)絡(luò)應(yīng)用程序,如服務(wù)器和客戶機(jī)。Netty大大簡(jiǎn)化了網(wǎng)絡(luò)編程,如TCP和UDP套接字服務(wù)器。 但很多學(xué)員都向小開(kāi)反應(yīng),一直在學(xué)Netty,但不得其法,學(xué)習(xí)的進(jìn)度很慢。4月27日的《HelloWorld公開(kāi)課》就是為了解決你的這個(gè)問(wèn)題,跟著宏彪老師,一節(jié)課讓你搞懂Netty。 Netty核心概念在正式開(kāi)始Netty學(xué)習(xí)前,我們先來(lái)了解幾個(gè)Netty框架中的核心概念,Channel(管道),其是對(duì)Socket的封裝,其包含了一組API,大大簡(jiǎn)化了直接與Socket進(jìn)行操作的復(fù)雜性。 EventLoopGroup是一個(gè)EventLoop池,包含很多的EventLoop。Netty為每個(gè)Channel分配了一個(gè)EventLoop,用于處理用戶連接請(qǐng)求、對(duì)用戶請(qǐng)求的處理等所有事件。EventLoop本身只是一個(gè)線程驅(qū)動(dòng)在其生命周期內(nèi)只會(huì)綁定一個(gè)線程,讓該線程處理一個(gè)Channel的所有IO事件。 ServerBootstrap用于配置整個(gè)Netty代碼,將各個(gè)組件關(guān)聯(lián)起來(lái)。服務(wù)端使用的是ServerBootstrap,而客戶端使用的是則Bootstrap。 ChannelHandler是對(duì)Channel中數(shù)據(jù)的處理器,這些處理器可以是系統(tǒng)本身定義好的編 解碼器,也可以是用戶自定義的。這些處理器會(huì)被統(tǒng)一添加到一個(gè)ChannelPipeline的對(duì)象中,然后按照添加的順序?qū)hannel中的數(shù)據(jù)進(jìn)行依次處理。 Netty中所有的I/O操作都是異步的,即操作不會(huì)立即得到返回結(jié)果,所以Netty中定義了一個(gè)ChannelFuture對(duì)象作為這個(gè)異步操作的“代言人”,表示異步操作本身。 如果想獲取到該異步操作的返回值,可以通過(guò)該異步操作對(duì)象的addListener()方法為該異步操作添加監(jiān)聽(tīng)器,為其注冊(cè)回調(diào):當(dāng)結(jié)果出來(lái)后馬上調(diào)用執(zhí)行。Netty的異步編程模型都是建立在Future與回調(diào)概念之上的。 Scoket編程定義服務(wù)端啟動(dòng)類 public class SomeServer { public static void main(String[] args) { // 創(chuàng)建一個(gè)group,用于處理客戶端連接請(qǐng)求 NioEventLoopGroup parentGroup = new NioEventLoopGroup(); // 創(chuàng)建一個(gè)group,用于處理客戶端連接上server后的后續(xù)請(qǐng)求 NioEventLoopGroup childGroup = new NioEventLoopGroup(); try { // bootstrap用于初始化channel ServerBootstrap bootstrap = new ServerBootstrap(); // 指定要使用的兩個(gè)group bootstrap.group(parentGroup, childGroup) // 指定要?jiǎng)?chuàng)建的channel的類型 .channel(NioServerSocketChannel.class) // 指定要使用的處理器 .childHandler(new ChannelInitializer<SocketChannel>() { // 初始化channel的方法 @Override protected void initChannel(SocketChannel ch) throws Exception { // channel一旦創(chuàng)建完畢,其就會(huì)同時(shí)綁定一個(gè)pipeline ChannelPipeline pipeline = ch.pipeline(); // 添加編碼器 pipeline.addLast(new StringEncoder()); // 添加解碼器 pipeline.addLast(new StringDecoder()); // 添加自定義的處理器 pipeline.addLast(new SomeServerHandler()); } }); // 創(chuàng)建channel,綁定到指定的主機(jī)(hostName,port) // sync()是將異步變同步 ChannelFuture future = bootstrap.bind(8888).sync(); System.out.println("服務(wù)器8888已經(jīng)啟動(dòng)。。。"); // 當(dāng)channel被關(guān)閉后,會(huì)觸發(fā)closeFuture()的執(zhí)行,去完成一些收尾工 作 future.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { // 將兩個(gè)group進(jìn)行優(yōu)雅關(guān)閉 parentGroup.shutdownGracefully(); childGroup.shutdownGracefully(); } } }123456789101112131415161718192021222324252627282930313233343536373839404142434445464748復(fù)制代碼類型:[java] 定義服務(wù)端處理器 // 自定義服務(wù)端處理器,用于處理來(lái)自于客戶端的數(shù)據(jù)public class SomeServerHandler extends ChannelInboundHandlerAdapter { // 一種回調(diào)方法:當(dāng)client將數(shù)據(jù)寫入到channel并發(fā)送到server后,server端就會(huì)觸發(fā)該方法的執(zhí)行 /** * * @param ctx 其代表當(dāng)前處理器(其實(shí)它是當(dāng)前處理器所封裝的一個(gè)節(jié)點(diǎn)) * @param msg 就是client端發(fā)送來(lái)的數(shù)據(jù) * @throws Exception */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // 輸出client的地址與發(fā)送來(lái)的數(shù)據(jù) System.out.println(ctx.channel().remoteAddress() + ", " + msg); // 向client發(fā)送一個(gè)隨機(jī)的UUID ctx.channel().writeAndFlush("from server: " + UUID.randomUUID()); TimeUnit.MILLISECONDS.sleep(500); } // 一旦在服務(wù)端發(fā)生異常,就會(huì)觸發(fā)該方法的執(zhí)行 @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); // 關(guān)閉channel ctx.close(); } }12345678910111213141516171819202122232425262728293031復(fù)制代碼類型:[java] Netty實(shí)現(xiàn)HTTP請(qǐng)求處理首先定義服務(wù)器啟動(dòng)類,該服務(wù)器用于創(chuàng)建并初始化服務(wù)器啟動(dòng)對(duì)象ServerBootStrap。 public class HttpServer { public static void main(String[] args) throws InterruptedException { EventLoopGroup parentGroup = new NioEventLoopGroup(); EventLoopGroup childGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(parentGroup, childGroup) .channel(NioServerSocketChannel.class) .childHandler(new HttpChannelInitializer()); ChannelFuture future = bootstrap.bind(8888).sync(); System.out.println("服務(wù)器啟動(dòng)了,端口號(hào)8888"); future.channel().closeFuture().sync(); } finally { parentGroup.shutdownGracefully(); childGroup.shutdownGracefully(); } } }1234567891011121314151617181920212223復(fù)制代碼類型:[java] 定義管道初始化器 public class HttpChannelInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new HttpServerCodec()); pipeline.addLast(new HttpServerHandler()); } }123456789復(fù)制代碼類型:[java]
講師介紹宏彪老師,原百度好看架構(gòu)師,現(xiàn)滬智科技技術(shù)合伙人 《Hello,World公開(kāi)課》是由開(kāi)課吧推出的面向廣大開(kāi)發(fā)工程師的免費(fèi)加餐課,集結(jié)業(yè)內(nèi)名師大咖,聚焦熱門技術(shù)和實(shí)戰(zhàn)解決方案,以專業(yè)知識(shí)分享交流為橋梁,鏈接正在創(chuàng)造世界的一群科技主力們,向初心致敬,為技術(shù)發(fā)燒。無(wú)論你是初入職場(chǎng)的應(yīng)屆生,還是準(zhǔn)備升職加薪的職場(chǎng)精英,相信這里都有你需要的養(yǎng)料。 |
|
來(lái)自: 碼農(nóng)9527 > 《Java》