Netty
一、概述
NIO的框架,主要是可以使系统在单线程的情况下可以同时处理多个客户端请求。主要是用了NIO的多路复用的技术
二、技术特点
零拷贝
Netty使用堆外直接内存进行Socket读写,不需要进行缓冲区的二次拷贝,如果使用传统内存,JVM会将内存Buffer拷贝一份到直接内存中,然后才写入Socket中
Netty提供了组合Buffer对象,可以聚合多个Buffer对象,避免了传统通过内存拷贝的方式将几个小Buffer合并成一个大的Buffer。
Netty的文件传输蚕蛹了transferTo方法,它可以直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环write方式导致的内存拷贝问题
内存池
为了解决堆外直接内存的分配和回收是一件耗时的操作,Netty提供了基于内存池的缓冲区重用机制
高效的Reactor线程模型
Reactor单线程模型,Reactor多线程模型,主从Reactor多线程模型
Reactor单线程模型
指所有的IO操作都在同一个NIO线程上面完成,NIO线程的职责如下
传统IO每个客户端对应一个服务端,每个连接创建成功后都需要一个线程来维护,每个线程包含一个while死循环
如果并发过多,传统IO就会创建越多的线程,这是非常消耗资源的。而且是阻塞式通信,频繁的线程切换,性能下降,而且IO是以字节流为单位,效率不高。
NIO编程
客户端连接channel,channel注册到selector中,每个channel都有一个selectkey,buffer通过selectkey来查找对应的channel来进行读写
所以NIO可以理解为非阻塞IO,新来一个连接,不再创建一个新的线程,而是把这条连接绑定到固定的线程,然后这条连接的所有读写都由这个线程来负责。
IO模型中,一个连接都会常见一个线程,对应一个while死循环,死循环的目的就是不断检测这条连接上是否有数据可以读。
NIO中可以把许多while死循环变成一个死循环,这个死循环由一个线程控制。这就是NIO模型中Selector的作用。来检测出有数据可读的连接。
NIO三大组件
通道、缓冲、选择器
通道:Stream升级版,Stream是单向的,读写分离,channel是双向的可以进行读的操作,也可以进行写的操作。
缓冲:内存区域存数据
选择器,监控多个信道,实现多路复用的效果。
NIO相对于IO的优势
IO是面向流的,每次操作都是操作系统底层一个字节一个字节的读取数据,并且数据只能从一段读取到另一端,NIO是面向缓冲区的,并且可以在缓冲区中前后移动
IO是阻塞的,当线程读取数据或者写数据时,该线程被阻塞,直到有一些数据被读取。在数据写完前,线程不能干别的事情。
NIO是非阻塞的,不需要一直等待操作完成才能干其他事情。而是在等待的过程中可以去做别的事情。可以最大限度的使用服务器的资源
NIO引入了IO多路复用器Selector,提供channel注册服务的线程,可以同时对接多个channel,并在线程池中为channel适配,选择合适的线程来处理channel,由于NIO模型中线程数量大大降低,线程切换效率也因此大幅度提高。
Netty
简单来说Netty封装了NIO,不用写一堆复杂的代码。异步事件驱动的网络应用框架。
Netty底层IO模型可以随意切换。
Netty自带的拆包解包,异常检测等机制,可以让使用者专心业务逻辑
解决了空轮询的bug
自带各种协议栈
健壮性强大。
使用就是导入依赖
Netty的事件驱动
例如很多系统会提供onClick事件,这个事件就代表鼠标按下事件。事件驱动模型:
1、有一个事件队列
2、鼠标按下时,往事件队列中增加一个点击事件
3、有个时间泵,不断循环从队列取出时间,根据不同的事件,调用不同的函数。
4、事件一般都各自保存各自的处理方法的引用。这样每个时间都能找到对应的处理方法
为什么使用时间驱动?
程序中的任务可以并行执行
任务之间高度独立,彼此之间不需要互相等待
在等待事件到来之前,任务不会阻塞
Netty使用时间驱动的方式作为底层架构,包括:
事件队列:接收事件的入口
分发器:将不同的事件分发到不同的业务逻辑单元
事件通道:分发器处理器之间的联系通道
事件处理器:实现业务逻辑,处理完成后会发出事件,触发下一步操作
Netty 功能特性:
-
传输服务,支持 BIO 和 NIO。
-
容器集成:支持 OSGI、JBossMC、Spring、Guice 容器。
-
协议支持:HTTP、Protobuf、二进制、文本、WebSocket 等,支持自定义协议。
具体实现:
服务端:
创建serverbootstrap来接收客户端的连接以及为已接收的连接创建子通道。
然后创建两个线程,一个负责接收新连接,一个负责读取数据的线程
服务端执行
要把两个线程放进去,
group就是把两个线程放进去,channel就是写一下channel对网络套接字的I/O操作,其实就是告诉这是服务端
channelInitialize对刚创建的通道进行初始化。
将channelHandler添加到channel的处理链路中
组件从流水线头部进入,流水线上的工人按顺序对组件进行加工。
流水线相当于channelpipeline
流水线工人相当于channelHandler
客户端:
一样的要先创建bootstrap
创建一个EventLoop实例,
客户端执行
要把group、channel、handler写一下
客户端连接服务端
使用while循环,用writeAndFlush发送数据。
具体使用就是前端写这个点击事件,向这个服务端发送消息。