一.netty服务端的启动
1.启动服务端Bootstrap,绑定group事件循环组,绑定channel为NioServerSocketChannel,绑定服务端handler,绑定客户端childHandler(1.1),绑定tcp的Option参数,还有attrs一般不会用
2.init和register服务端channel,init创建一个channel,绑定各种参数和pipeline。pipeline添加自定义handler后,起线程添加ServerBootstrapAcceptor这个inboundhandler
3.ServerBootstrapAcceptor是一个入栈handler,重写channelRead方法,msg中接收客户端channel(3.1),绑定客户端channel的各种参数和pipeline,并将客户端channel注册到childGroup线程上,监听客户端事件。
4.服务端channel虽然只有一个,但是也有它自己的ctx、handler及pipeline,handler就是ServerBootstrapAcceptor,当服务端channel有事件发生时,消息经过pipeline到达ServerBootstrapAcceptor,以此绑定客户端channel。
5.doBind0调用java nio底层进行register
6.上述就完成了:NioServerSocketChannel绑定到事件循环组,进行了底层nio地址端口相关的注册,事件循环组会持续运行,接收客户端消息进行SocketChannel的处理。

1.1 绑定handler使用ChannelInitializer,实现其initChannel方法,在该方法里将handler添加到pipeline。initChannel方法会被调用,调用时机为handlerAdded的时候(ChannelHandler被添加到Pipeline后,在addFirst方法里会触发一个handlerAdded回调)

3.1 接收到的客户端channel何时创建:二.4

二.接收客户端连接
1.NioServerSocketChannel所在的事件循环组NioEventLoopGroup中的NioEventLoop是一个一直监听channel连接事件的线程,在run方法的processSelectedKeys()遍历消息。
2.NioEventLoop <= channel => nio
3.遍历selectedKeys大于0时,进入处理流程。此处selectedKeys是netty自身的,在openSelector()中用反射将nio的替换掉,当nio接收到消息后,selectedKeys增长
4.客户端建立连接时,事件为SelectionKey.OP_ACCEPT,NioServerSocketChannel的unsafe为AbstraceNioMessageChannel。此事件中简单创建SocketChannel,把SocketChannel作为参数用fireChannelRead传递给handler,也就是ServerBootstrapAcceptor,在其中完成了绑定参数和pipeline、注册到childGroup,此后开始监听该SocketChannel的事件。
5.上述完成了客户端channel的注册绑定,也理解了netty的线程模型为建立连接和具体消息由不同NioEventLoop处理。

三.接收客户端消息
1.同上,NioEventLoop循环遍历selectedKeys
2.当事件发生时,NioSocketChannel的unsafe为NioSocketChannelUnsafe,消息读取到ByteBuf中后,byteBuf作为参数传递到pipeline的handler中
3.第一个handler是head handler,不做处理透传消息到下一个handler,比如websocket解码handler:WebSocket13FrameDecoder,在这里会将原始的byte数据解码为websocket帧,包装成websocket相关的类,继续传递到下一个handler

四.DefaultChannelPipeline
1.pipeline创建的构造方法中同时创建了head和tail,head和tail分别为HeadContext和TailContext,这俩handler在DefaultChannelPipeline中定义,基本不做什么事情,头传递消息到下一个handler,尾释放资源
2.DefaultChannelPipeline的tostring方法去掉了头和尾,所以debug的时候只能看到中间的handler
3.pipeline中的增删查改替换操作,实现了ctx的顺序,间接实现了handler的顺序。
4.pipeline中的fire系列方法都要从head ctx开始,走一遍pipeline,一般应该用不着
5.默认的pipeline在channel创建的时候绑定到了channel上,后面可以扩增和删减

五.AbstractChannelHandlerContext
1.可以拿到channel、pipeline等信息(1.1)
2.消息从入口ctx,经过fireChannelRead方法经过了每一个ctx,因为ctx知道它的下一个ctx是谁,也知道该ctx中的handler是inbound还是outbound。
3.所以我们自己写的handler中,如果想传递消息到下一个handler,只需要使用ctx的fireChannelRead方法。
4.ctx是当pipeline增加、替换ctx时newContext方法创建的,顺便将handler绑定了进去

1.1 Context、handler、pipeline、channel的交杂关系
客户端建立连接后创建了channel,channel有一个pipeline,pipline中原始包含head和tail两个context,也同时是两个handler,pipeline主要管理context的先后顺序,可以进行设置和调整。context中的next和prev是下一个和上一个context,每个context中包含了一个handler。它们的由来顺序为:channel - pipeline - ctx - handler

六.Channel
1.此处Channel是netty的新东西,它的底层使用的还是java nio的SocketChannel,相当于是一个功能扩展类
2.在NioSocketChannel中可以看到大量地方用javaChannel()获取到nio的SocketChannel;Channel中的属性也有很多套用了nio底层的东西
3.NioSocketChannel的父类AbstractNioChannel中有一个属性是SelectableChannel,这就是实际的nio channel,所以NioSocketChannel可以对nio channel进行状态查询、操作。channel判断是否active就是对nio channel查询状态以后netty自己包装出了active的含义
4.监听器:netty重新写了一个future类作用为可以收到发送消息后的结果。netty使用添加listener的方式回调到业务方法里,由我们自己进行得到结果后的处理。给ChannelFuture添加一个listener,重写GenericFutureListener中的方法operationComplete,当数据flush完毕后,会触发这个operationComplete方法回调

七.Handler
1.分为入栈和出栈handler,入栈接收建立连接请求、消息,出栈发送消息。
2.io.netty.handler路径下有netty提供的大量handler,也可以自己写handler
3.handler被ctx包含和管理,handler负责业务处理,而ctx链路是一个链式结构,管理handler的执行时机
4.接收消息时,消息首先到达head handler,不做处理传递到下一个handler,直到最后tail handler释放资源。发送消息时,消息首先通过tail ctx的发送方法,进入ctx的发送流程,从尾部往前面handler,直到head handler调用unsafe的发送方法进行实际的发送

八.发送消息到客户端
此处仅说明writeAndFlush的方法发送消息
1.和接收消息一样会调用到pipeline的handler中,只不过接收消息是从到尾,发送消息是从尾到头。
2.channel.writeAndFlush会将消息传递到尾handler,尾handler向前查找出栈handler,找到的话判断当前线程是否netty线程(2.1),不是的话新创建一个WriteAndFlushTask线程,在线程run方法执行写操作
3.如果用到了ChunkedWriteHandler,会在flush中用ctx.write继续查找下一个handler并编码和传递消息
4.write的时候不会直接发送消息到客户端,flush的时候才会将outboundBuffer消息实际发出去,头handler的flush使用unsafe的方法进行发送

2.1 一般我们不在netty的io线程中发送消息,所以这个时候一定是要新创建一个线程的

pipeline示例:
http:
(HttpServerCodec#0 = io.netty.handler.codec.http.HttpServerCodec),
(ChunkedWriteHandler#0 = io.netty.handler.stream.ChunkedWriteHandler),
(HttpObjectAggregator#0 = io.netty.handler.codec.http.HttpObjectAggregator),
(NettyWsHandler#0 = com.hikvision.inms.wss.netty.NettyWsHandler),
(io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandshakeHandler = io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandshakeHandler), (io.netty.handler.codec.http.websocketx.Utf8FrameValidator = io.netty.handler.codec.http.websocketx.Utf8FrameValidator),
(WebSocketServerProtocolHandler#0 = io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler)
websocket:
(wsencoder = io.netty.handler.codec.http.websocketx.WebSocket13FrameEncoder),
(wsdecoder = io.netty.handler.codec.http.websocketx.WebSocket13FrameDecoder),
(ChunkedWriteHandler#0 = io.netty.handler.stream.ChunkedWriteHandler),
(NettyWsHandler#0 = com.hikvision.inms.wss.netty.NettyWsHandler),
(WS403Responder = io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler$1),
(io.netty.handler.codec.http.websocketx.Utf8FrameValidator = io.netty.handler.codec.http.websocketx.Utf8FrameValidator),
(WebSocketServerProtocolHandler#0 = io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler)