一.ServerBootstrap:
Netty引导类,初始化类,分别有两个一个服务端的,一个客户端的
二.父子channel
在Netty中,Channel是一个Socket连接的抽象,它为用户提供了关于底层Socket状态(是否是连接还是断开)以及对Socket的读写等操作.每当Netty建立了一个连接后,都会有一个对应的Channel实例。
并且,有父子channel的概念。服务器连接监听的channel,也叫parent channel。对应于每一个Socket连接的channel,也叫child channel.
三.EventLoop线程与线程组
1.NioEventLoop来表示一个不断循环执行处理任务的线程,每个NioEventLoop聚合一个多路复用器selector,用于监听绑定在其上的socket链路,因此可以处理多个客户端连接
2.netty采用串行化设计理念,从消息的读取->解码->处理->编码->发送,始终由IO线程NioEventLoop负责。整个流程不会进行线程上下文切换,数据无并发修改风险。
3.NioEventLoop中的Thread线程按照时间轮中的步骤不断循环执行:
①在时间片Tirck内执行selector.select()轮询监听IO事件;
②处理监听到的就绪IO事件;
③执行任务队列taskQueue/delayTaskQueue中的非IO任务
4.几个对象的关系:
一个NioEventLoopGroup下包含多个NioEventLoop
每个NioEventLoop中包含有一个Selector,一个taskQueue,一个delayedTaskQueue
每个NioEventLoop的Selector上可以注册监听多个AbstractNioChannel
每个AbstractNioChannel只会绑定在唯一的NioEventLoop上
每个AbstractNioChannel都绑定有一个自己的DefaultChannelPipeline
5.Server端NioEventLoop处理的事件
6.Client端NioEventLoop处理的事件
四.channel协议类型
除了TCP协议以外,Netty还支持很多其他的连接协议,并且每种协议还有NIO(异步IO)和OIO(Old-IO,即传统的阻塞IO)版本的区别,不同协议不同的阻塞类型的连接都有不同的Channel类型与之对应,下面是一些常用的 Channel类型:
①NioSocketChannel,代表异步的客户端TCP Socket连接.
②NioServerSocketChannel,异步的服务器端TCP Socket连接.
③OioSocketChannel,同步的客户端TCP Socket连接.
④OioServerSocketChannel,同步的服务器端TCP Socket连接.
⑤NioDatagramChannel,异步的UDP连接
⑥OioDatagramChannel,同步的UDP连接
⑦NioSctpChannel,异步的客户端Sctp连接.
⑧NioSctpServerChannel,异步的Sctp服务器端连接.
⑨OioSctpChannel,同步的Sctp服务器端连接.
⑩OioSctpServerChannel,同步的客户端TCP Socket连接.
五.ChannelInitializer,ChannelPipeline,ChannelHandler
Netty提供了一种将多个ChannelHandler添加到一个ChannelPipeline中的简便方法。你只需要简单地向Bootstrap或ServerBootstrap的实例提供你的ChannelInitializer实现即可,并且一旦Channel被注册到了它的EventLoop之后,就会调用你的initChannel()版本。在该方法返回之后,ChannelInitializer的实例将会从ChannelPipeline中移除它自己。
ChannelPipeline: 类似于拦截器链
ChannelPipeline是一个拦截流经Channel的入站和出站事件的ChannelHandler实例链。每一个新创建的Channel都将会被分配一个新的ChannelPipeline。这项关联是永久性的;Channel既不能附加另外一个ChannelPipeline,也不能分离其当前的。在Netty组件的生命周期中,这是一项固定的操作,不需要开发人员的任何干预。根据事件的起源,事件将会被ChannelInboundHandler或者ChannelOutbboundHandler处理。随后,通过调用ChannelHandlerContext实现,它将被转发给同一超类型的下一个ChannelHandler。
执行顺序: 对于进站事件来说,先添加的先执行.对于出站事件来说,后添加的先执行。
ChannelInboundHandler(入站): 处理输入数据和Channel状态类型改变。
ChannelOutboundHandler(出站): 处理输出数据
六.ChannelHandlerContext,AttributeMap
每一个ChannelHandlerContext都是ChannelHandler和ChannelPipeline之间连接的桥梁,ChannelHandlerContext就是ChannelHandler上下文
AttributeMap相对于一个map,AttributeKey相当于map的key,Attribute是一个持有key(AttributeKey)和value的对象。因此在map中我们可以通过AttributeKey key获取Attribute,从而获取Attribute中的value(即,属性值)。
七.Netty主要几个对象关系图:
八.TCP粘包,拆包问题
熟悉TCP编程的可能都知道,无论是服务器端还是客户端,当我们读取或者发送数据的时候,都需要考虑TCP底层的粘包/拆包机制。
TCP是一个“流”协议,所谓流就是没有界限的遗传数据。大家可以想象一下,如果河水就好比数据,他们是连成一片的,没有分界线,TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的具体情况进行包的划分,也就是说,在业务上一个完整的包可能会被TCP分成多个包进行发送,也可能把多个小包封装成一个大的数据包发送出去,这就是所谓的粘包/拆包问题.
解决方案:
1.消息定长,例如每个报文的大小固定为200个字节,如果不够,空位补空格。
2.在包尾部增加特殊字符进行分割,例如加回车等。
3.将消息分为消息头和消息体,在消息头中包含表示消息总长度的字段,然后进行业务逻辑的处理。
4.Netty中解决TCP粘包/拆包的方法:
①分隔符类:DelimiterBasedFrameDecoder(自定义分隔符)
②定长:FixedLengthFrameDecoder