Netty(三)建立服務端
1、服務端時序圖:
2、編碼流程:
- 建立ServerBootstrap例項
- 設定EventLoopGroup
- 設定建立的Channel型別
- option配置屬性
- 設定Handler,處理請求
- 設定ChildHandler,處理對應channel的請求
- 通過bind建立Chnnel並繫結,啟動服務
serverBootstrap = new ServerBootstrap(); eventLoopGroup = new NioEventLoopGroup(); serverBootstrap.group(eventLoopGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_KEEPALIVE, true) .handler(new LoggingHandler(LogLevel.INFO));
設定Handler,處理請求
設定ChildHandler,處理對應channel的請求
通過bind建立Chnnel並繫結,啟動服務
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel sc) throws Exception { sc.pipeline() .addLast(new ProtocolDecoder(chargeDevice)) .addLast(new ProtocolEncoder()) .addLast(new IdleStateHandler(readerIdleTime, writerIdleTime, allIdleTime, TimeUnit.SECONDS)) .addLast(new MyInboundHandler(chargeDevice)); } }); this.channelFuture = serverBootstrap.bind(port).sync();
3、服務端重要元件
(1)ServerBootstrap
ServerBootstrap是Netty服務端的啟動輔助類,提供一系列的方法用於設定服務端的引數和配置,簡化開發。(衍生一點:ServerBootstrap的構造方法是無參的,因為引數太多所以採用了Builder模式)
繼承自AbstractBootstrap,核心屬性有childGroup和childHandler。
- childGroup:負責排程和執行客戶端的接入、網路讀寫事件的處理、使用者自定義任務和定時任務的執行
- childHandler:自定義的業務Handler
AbstractBootstrap核心屬性有group和handler。
- group:處理客戶端的連結請求,並轉交給childGroup(讀取的資料是穿件的NioSocketChannel)
(2)Reactor執行緒池
Netty的Reactor執行緒池是EventLoopGroup,實際上是一個EventLoop的陣列。
EventLoop的職責是處理所有註冊到本執行緒多路複用器Selector上的Channel,Selector的輪訓操作有EventLoop執行緒run方法驅動。
另外使用者自定義的Task和定時任務Task也由統一的EventLoop負責處理。
(3)Channel
作為Nio服務,需要建立ServerSocketChannel,Netty對原生NIO類庫做了封裝,對應實現類為NioServerSocketChannel。
使用者只需要制定Channel的實現型別,內部通過反射機制來建立對應的例項。
因為只在監聽埠時建立,所以反射的效能影響並不大。
(4)ChannelPipeline
ChannelPipeline是網路事件處理的職責鏈,負責管理和執行ChannelHandler。網路事件以事件流的形式在ChannelPipeline中流轉。
(5)ChannelHandler
ChannelHandler是提供給使用者定製和擴充套件的關鍵介面,包括編解碼,業務處理等都是通過ChannelHandler進行的。
(6)Selector
Selector輪訓操作由NioEventLoop排程和執行,選擇準備就緒的Channel集合。
(7)NioServerSocketChannel
繫結Server端地址的Server,讀取客戶端的連結請求(只有一個,在bind時建立)。
(8)NioSocketChannel
和客戶端之間的連結。
4、例項
public class NettyServer {
public void bind(int port){
// 建立EventLoopGroup
EventLoopGroup bossGroup = new NioEventLoopGroup(); //建立BOSS執行緒組 用於服務端接受客戶端的連線
EventLoopGroup workerGroup = new NioEventLoopGroup(); //建立WORK執行緒組 用於進行SocketChannel的網路讀寫
try {
// 建立ServerBootStrap例項
// ServerBootstrap 用於啟動NIO服務端的輔助啟動類,目的是降低服務端的開發複雜度
ServerBootstrap b = new ServerBootstrap();
// 繫結Reactor執行緒池
b.group(bossGroup, workerGroup)
// 設定並繫結服務端Channel
// 指定所使用的NIO傳輸的Channel
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.handler(new LoggingServerHandler())
.childHandler(new ChannelInitializer(){
@Override
protected void initChannel(Channel ch) throws Exception {
//do something
}
});
// 繫結埠,同步等待成功
ChannelFuture future = b.bind(port).sync();
// 等待服務端監聽埠關閉
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 優雅地關閉
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private class LoggingServerHandler extends ChannelInboundHandlerAdapter{
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("loggin-channelActive");
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("loggin-channelRegistered");
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("loggin-handlerAdded");
}
}
public static void main(String[] args){
new NettyServer().bind(8899);
}
}