1.什么是Netty?Netty的应用场景是什么?
a.Netty是一个基于NIO的客户端服务器框架,使用他可以快速简单的开发网络应用程序
b.极大的简化了TCP/UDP等网络编程,且支持各种协议,性能更好
应用场景:
a.作为RPC框架的网络通信工具(分布式系统中,不同服务中经常需要经常互相调用),此时不同服务节点的通信就是基于Netty来完成的!
2.Netty的核心组件有哪些?分别是干嘛的?
Channe接口:
网络操作抽象类,主要是包括基本的I/O操作 常用的接口实现类是NioServersSocketChannel(服务端)和NioSocketChannel(客户端);
EventLoop与EventloopGroup:
EventLoop的主要作用就是负责网络监听事件并且调用事件处理器进行相关I/O操作,负责处理注册到其上的 Channel 处理 I/O 操作,两者配合参与 I/O 操作。
ChannelFuture:
因为Netty都是异步非阻塞的,所以I/O操作都为异步的,因此我们不能立刻得到操作是否执行成功,此时可以通过此接口的addListener()方法注册一个ChannelFutureListener,当操作执行成功或者失败的时候 ,监听会自动触发并且返回结果;
ChannelHandler与ChannelPipeline:
ChannelHandler 是消息的具体处理器。他负责处理读写操作、客户端连接等事情;
Bootstrap与ServerBootstrap:
Bootstrap为客户端辅助启动类,ServerBootstrap为服务端辅助启动类;
同时Bootstrap通常使用connect()方法连接到远程的主机和端口,作为一个Netty TCP协议通信的客户端;而ServerBootstrap通常使用bind()方法绑定本地的端口上等待客户端的连接;
同时Bootstrap只需要配置一个线程组-EventLoopGroup,而ServerBootstrap需要配置两个线程组,一个用于接收一个用于处理事务;
3.Netty线程模型(使用EventLoopGroup类的无参构造函数线程数默认为CPU核心数*2)
单线程模型:
一个线程要完成执行处理所有的accep,read,decode....事件 不适用于高负载,高并发场合
多线程模型:
一个Acceptor线程专门负责监听客户端的连接,还要一个NIO线程池负责具体处理accep,read,decode....能满足绝大多数的场景 如果并发连接大就会出现问题 成为性能瓶颈
第一个线程bossGroup的创建 用于连接 第二个线程workGroup的创建是用于具体的处理
主从多线程模型:
从一个主线程NIO线程池子中选择一个线程作为Acceptor线程,绑定监听端口,监听客户端连接,其他线程负责后续的接入认证工作。连接建立完成后,Sub Nio线程池负责具体处理I/O读写
4.Netty服务端与客户端的启动过程
服务端:
1.先创建了两个EventGroup的对象实列:bossGroup(处理客户端的TCP连接)与workGroup(负责每一条连接的具体读写数据的处理逻辑,真正负责I/O读写操作,交由对应的Handler处理)
2.接下来创建一个服务端启动引导、辅助类(ServerBootstrap),引导进行服务端启动工作
3.通过调用.group()方法将引导类配置两大线程组(bossGroup,workGroup),确定线程模型
4.通过channel()方法指定服务端的IO模型为NIO(NIOServerSocketChannel)以及置顶客户端的IO模型为NIO(NioSocketChannel)
5.通过.childHandler()方法给引导类创建一个ChannelInitializer,然后指定了服务端消息的业务处理逻辑HelloServerHandler对象
6.调用ServerBootstrap类的bind()方法绑定端口并可以通过sync方法阻塞知道绑定完成
客户端:
1.创建一个NioEventLoopGroup对象实列
2.创建客户端的起动引导类是Bootstrap
3.通过.group()方法给引导类配置一个线程组
4.通过Channel()方法给引导类指定了IO模型为NIO
5.通过.childHandler()给引导类创建一个ChannelInitializer,然后同时指定客户端消息的业务处理逻辑HelloClientHandler对象
6.调用Bootstrap类的connect()方法进行连接(返回Future类型对象)同时需要指定ip地址和端口号两个参数
5.TCP粘包和拆包如何解决?
主流的解决方法:
a.消息定长例如每个报文的大小固定长度200字节,如果不够,空位补空格
b.在包尾增加回车换行符进行分割,例如FTP协议
c.将消息分为消息投和消息体,消息头中包含表示消息总长度(或者消息体长度)的字段,通常设计思路为消息头第一个字段使用it32来表示消息的总长度;
项目的解决方案:
1.通过DelimiterBasedFrameDecoder+StringDecoder解决粘包的问题,设置分隔符和获取数据的最大值来解决粘包问题
2.DelimiterBasedFrameDecodel的工作原理是它依次遍历Bytebufr中的可读字节,判断看是否有设置的分隔符(“\r\n”)如果有,就以此位置为结束位置,从可读索引到结束位置区间的字节就组成了一行。它是以换行符为结束标志的解码器,支持携带结束符或者不携带结束符两种解码方式,同时支持配置单行的最大长度。如果连续读取到最大长度后仍然没有发现换行符,就会抛出异常,同时忽略掉之前读到的异常码流。
3.String Decoder的功能非常简单,就是将接收到的对象转换成字符串然后继续调用后面Handler。DelimiterBasedFrameDecode+String Decoder组合就是按行切换的文本解码器,它被设计用来支持TCP的粘包和拆包;
6.Netty长连接与心跳机制
什么是心跳机制?以及为什么需要心跳机制?
a.这就要涉及到TCP的长连接与短链接(连接:三次握手 断开:四次挥手)短链接带来的缺点就是每次建立连接都要大量消耗资源和时间的浪费
b.在使用长连接的情况下,当client与server长时间没有数据交互时(即此刻处于idle状态时),客户端或服务端就会发送一个特殊的数据包给对方,当接收方收到这个报文后就会理解发送一个特殊报文来回应给发送方,所以这就是PING-PONG交互 心跳消息知道对方仍在线,确保TCP连接的有效性;netty实现心跳机制的核心类是IdleStateHandler;