关闭之前流程为:
1.多路复用器(Selector) 接收到OP_ READ事件:
2.处理OP_ READ事件: NioSocketChannel.NioSocketChannelUnsafe.read()
调用NioSocketChannelUnsafe,这个类里面有个重载方法prepareToClose(),官方介绍为“We need to cancel this key of the channel so we may not end up in a eventloop spin, because we try to read or write until the actual close happens which may be later due, SO_LINGER handling.” 意思大概就是我先去试下读或者写,看看你是不是骗我的,失败了才是真正的关闭
优雅的关闭动作:
unbind netty创建的所有channel。channel.unbind()
close netty创建的所有channel。channel.close()
shutdown netty的线程执行器。factory.releaseExternalResources()
本质是
1.先关channel (包含cancel多路复用器的key)
2.清理消息:新消息全部不给进,队列里的消息也全部清掉
3.触发fireChannellnactive和fireChannelUnregistered
close方法中,客户端发出正常的挥手请求,执行pipeline里面的inactive和unregister方法,即停止运行和取消注册。当然也有做优化--》即关闭连接到一定数量(阀值)的时候,后面的链接可能也相应的关掉了,所以就重新检查下所有的连接有没有关闭,可以减少关闭那些已经被关闭的连接所用的时间
而异常关闭,客户端来不及发出挥手请求,发出的是RST复位请求,服务端在刚才说的unsafe.read方法中doReadBytes(byteBuf)这句直接抛出I/O异常,被捕捉后进入handleReadException方法,在方法中有fireExceptionCaught调用pipeline的exceptionCaught方法,而fireExceptionCaught下面还有之前说的closeOnRead,执行pipeline里面的inactive和unregister方法。
和read write一样,关闭的本质还是调用了jdk的java.nio.channels.spi.AbstractInterruptibleChannel
的close方法,看清了,不是sun.nio.ch.SocketChannelImpl