1、netty客户端与服务端的通信流程
new ServerBootstrap()
.group(new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
// 添加一个channel初始化handle,handle就是一道一道的工序,来处理传输到服务端的数据,他们都是按循序执行的,并且是交给nioevent中的线程来执行
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
// pipeline是channel的一个属性,他可以绑定很多的handle.
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
log.info(msg.toString());
}
});
// 这两个handle都是由nio线程来执行的,如果有些handle比较耗费时间,那么此时我们可以创建defaulEventLoopGroup来执行handle的任务,只需要在匿名类中指定一个默认事件循环组,不然会影响io线程处理读写事件的性能,并且handle执行链不是由相同的线程执行的话,还需要额外添加一行代码。
}
})
.bind(8085)
.sync();
serversocketchannel可以有两个时间循环组,一个BossEventLoop一个WorkEventLoop。
其实BossEventLoop只关注Accept事件,Work只关心读和写的事件。
他们都会轮询,模型是reactor的主从多线程模式,但是netty在此基础改进了,也可以有多个线程来处理accept事件,然后会建立起socket连接,当发生读写事件时,此时就交给Work组的线程去完成。
handle如果调用链不属于同一个线程,那么则会通过判断下一个handle所属的eventloop和当前线程是否是同一个线程,来决定是当前线程执行还是用下一个handle来提交一个任务,让别的线程执行。
这样做的目的是?
带有Future、Promise的类型都是异步方法配套使用,异步方法的调用者并不关心其运行结果,就以客户端的建立链接的connect()方法为例,这是一个异步方法,是由main线程发起调用的,但是建议socket连接本身就需要花费不少时间,所以当主线程调用到channel的方法时,此时的channel还有没有与服务端建立链接,所以无论怎么调用服务端都不会收到数据,调用sync()会阻塞住当前线程,直到nio线程的connect连接建立。
netty为什么要用异步的方式去处理建立连接,优雅的释放资源,关闭链接呢?