Netty是基於CS架構的一種模式,分爲Client端和Server端
(1)先從Server端開始,先看一下Netty服務端的運行原理圖:
首先你得知道下面的幾個主要的角色:
- serverBootstrap
- NioEventLoopGroup (這個是專門負責接收client端的請求的)
- NioEventLoopGroup (這個是專門負責幹活的)
- NioServerSocketChannel (當和client建立連接之後,生成NioSocketChannel,並將NioSocketChannel註冊到某個worker NioEventLoop的selector上)
然後就是具體的執行Netty服務端的具體執行流程:
- 首先server端啓動時綁定本地某個端口,初始化channel,其實就是生成channel的實例對象NioServerSocketChannel。
- 然後將自己NioServerSocketChannel註冊到某個bossGroup(其實就是讓前臺經理先去接待)的NioEventLoop的selector上,每個NioEventLoop包含1個selector和1個事件循環線程
- 然後進入到bossGroup的循環線程中,其實就是他要怎麼去處理這個“接待”的過程
- 第一步bossGroup需要去輪詢accept事件,
- 第二步就是去處理IO事件,然後和client建立連接,生成NioSocketChannel,並將NioSocketChannel註冊到某個workerGroup NioEventLoop的selector上
- 第三步處理任務隊列中的任務,runAllTasks。任務隊列中的任務包括用戶調用eventloop.execute或schedule執行的任務,或者其它線程提交到該eventloop的任務
- 完事之後任務就開始進入到了wrokGroup線程組中來去真正的幹活了,因爲他也是一個線程組
- 第一步是先輪詢read、write事件
- 第二步就開始處理io任務,即read、write事件,在NioSocketChannel可讀、可寫事件發生時進行處理
- 第三步還是處理任務隊列中的任務,runAllTasks
這是Netty服務端的基本使用的模板代碼:
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
//可以把這個看成是一個大Boss負責把這個公司的環境給搭建好,把人員給各就各位
ServerBootstrap serverBootstrap = new ServerBootstrap();
//這個相當於前臺經理Boss(主要負責接待),這個組裏包含多個事件循環,每個NioEventLoop包含1個selector和1個事件循環線程
NioEventLoopGroup boosGroup = new NioEventLoopGroup();
//這個就是worker線程組,相當於技術經理主要負責產出
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
//這個其實就是綁定端口,初始化各種組件
try {
ChannelFuture channelFuture = serverBootstrap
//前者是一個父線程池事件組,後者參數是子線程池事件組(其實就是專門用來處理具體的任務的)
.group(boosGroup, workerGroup)
//指定 Channel 的類型. 因爲是服務器端, 因此使用了 NioServerSocketChannel.
.channel(NioServerSocketChannel.class)
//設置數據的處理器.
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
System.out.println("打印管道中的信息----->" + msg);
}
});
}
})
.bind(9090).sync();
}finally {
//這裏是關閉線程組
boosGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
(2)然後是Client端的clientServer的代碼,看一下他的原理運行圖:
ClientServer端的運行原理流程:
- 首先ClientServer端也是需要去進行一些初始化,然後通過connect()方法去綁定服務器端的ip地址和端口,然後也需要去初始化channel的實例對象NioSocketChannel,和Server端差不多,但是不同的是ClientServer端只需要一個線程事件組就可以了,NioEventLoop也是需要三步來完成.
- 第一步輪詢connect、read、write事件;
- 第二步處理io任務,即connect、read、write事件,在NioSocketChannel連接建立、可讀、可寫事件發生時進行處理
- 第三步:處理非io任務,runAllTasks
ClientServer端的代碼模板:
public class NettyClient {
public static void main(String[] args) throws InterruptedException {
Bootstrap bootstrap = new Bootstrap();
//這裏是定義一個事件組,其實本質就是他的父類MultithreadEventExecutorGroup維護了一個線程池 EventExecutor children
NioEventLoopGroup group = new NioEventLoopGroup();
bootstrap.group(group)
//指定 Channel 的類型. 因爲是客戶端, 因此使用了NioSocketChannel. Channel 是通過工廠方法 ChannelFactory.newChannel()
.channel(NioSocketChannel.class)
//設置數據的處理器.
.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) {
ch.pipeline().addLast(new StringEncoder());
}
});
//連接服務器地址和端口並且綁定通道
Channel channel = bootstrap.connect("127.0.0.1", 9090).channel();
while (true) {
channel.writeAndFlush(new Date() + ": hello world!");
channel.write("客戶端向服務器中的管道中寫入數據------>");
Thread.sleep(2000);
}
}
}
Netty的NIO模型: