通過Netty入門,可以運(yùn)行和啟動(dòng)一個(gè)簡單的客戶端和服務(wù)端的應(yīng)用了,這里看下Netty每個(gè)組件的細(xì)節(jié),以及組件之前是如何協(xié)作的。
實(shí)例
我們先看代碼:注釋中包含了使用Netty服務(wù)端的一些操作說明,剛學(xué)的時(shí)候不太明白這些東西的意思,但是看了Netty的組件設(shè)計(jì),及其架構(gòu),就容易理解每個(gè)語句對應(yīng)的意思。
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
// 服務(wù)端的BootStrap,一個(gè)需要接受連接,一個(gè)用來處理事件
b.group(bossGroup, workerGroup)
// Channel理解為通道,網(wǎng)絡(luò)傳輸?shù)耐ǖ李愋? .channel(NioServerSocketChannel.class)
// ChannerlHandler要被裝進(jìn)ChannelPipeline
// 而過程則是調(diào)用ChannelInitializer的iniChannel方法
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch)
throws Exception {
// addLast,在PipeLine中的Handler是有順序的,所以
// 有addLast,addFirst等方法
// 添加的同時(shí),可以指定Encoder和Decoder
ch.pipeline().addLast(new RequestDecoder(),
new ResponseDataEncoder(),
new ProcessingHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
// TODO 待細(xì)看,先當(dāng)做固定的寫法
ChannelFuture f = b.bind(port).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
客戶端與服務(wù)端基本一致,只是將綁定本地端口換成了連接遠(yuǎn)端的端口
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
// 配置ChannelHandler
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(new RequestDataEncoder(),
new ResponseDataDecoder(), new ClientHandler());
}
});
ChannelFuture f = b.connect(host, port).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
}
下面是看Netty In Action一書中整理到的其組件設(shè)計(jì)的一些知識(shí)點(diǎn)。
Netty網(wǎng)絡(luò)層
Channel,EventLoop,ChannelFuture可以看做Netty的網(wǎng)絡(luò)抽象層
- Channel - Socket
- EventLoop - 控制流,多線程,并發(fā)
- ChannelFuture - 異步通知
Channel接口
基礎(chǔ)的IO操作,bind,connect,read,write. 在底層上,這些主要依賴Java的Socket,Netty的Channel封裝了底層的復(fù)雜操作。使得用起來簡化很多,它提供了很多預(yù)定義的特定場景下的實(shí)現(xiàn)。

EventLoop接口
EventLoop接口定義了連接的整個(gè)生命周期中的事件處理,下圖解釋了Channel,EventLoop,Threads和EventLoopGroup的關(guān)系

- EventLoopGroup包含一個(gè)或多個(gè)EventLoop
- EventLoop的整個(gè)生命周期與單個(gè)線程的生命周期一致
- Channel注冊它的生命周期到單個(gè)的EventLoop上
- 單個(gè)EventLoop能分配一個(gè)或多個(gè)Channel
- 所有的I/O事件被EventLoop處理
ChannelFuture
在Netty中,所有的IO操作都是異步的,因?yàn)椴僮鞑皇橇⒖谭祷亟Y(jié)果,我們需要一個(gè)方式在程序執(zhí)行一會(huì)再獲取結(jié)果。Netty提供了ChannelListener,它的addListner方法注冊一個(gè)ChannelFutureListener,當(dāng)操作完成的時(shí)候就會(huì)通知Listener。
ChannelHandler and ChannelPipeline
這兩個(gè)組件用來管理數(shù)據(jù)流和執(zhí)行應(yīng)用的邏輯。
ChannelHandler
從開發(fā)者的角度來看,Netty最主要的組件就是ChannelHandler,它可以處理應(yīng)用內(nèi)輸入和輸出的數(shù)據(jù)流,基本上可以做任意類型的數(shù)據(jù)操作,例如數(shù)據(jù)格式轉(zhuǎn)換,或者異常處理。
ChannelPipeline
ChannelPipeline提供了ChannelHandler的容器,其內(nèi)部可以有多個(gè)ChannelHandler,定義了鏈?zhǔn)紺hannelHandler傳播輸入數(shù)據(jù)和輸出數(shù)據(jù)流的API。當(dāng)Channel被創(chuàng)建的時(shí)候,它會(huì)自動(dòng)的分配到ChannelPipeline。
- ChannelInitializer的實(shí)現(xiàn)被注冊到ServerBootstrap
- 當(dāng)ChannelInitializer.initChannel被調(diào)用,就將多個(gè)ChannelHandler安裝到pipeline中
- ChannelInitializer將自己從ChannelPipeline中移除
ChannelHandler可以看做是代碼的容器,里面主要都是我們的程序邏輯,處理事件還有在ChannelPipeline中的數(shù)據(jù),ChannelHandler主要被添加進(jìn)ChannelPipeLine中,當(dāng)它被添加的時(shí)候會(huì)被分配一個(gè)ChannelHandlerContext。
小結(jié)
這里主要介紹了Netty的一些基本組件。
參考
- 《Netty in Action》