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