Netty⼊门教程——深⼊浅出Netty
在这⾥我们主要从TCP应⽤部分讲述 Netty 的架构体系。
它涉及到的内容主要分为三个部分 : bootstrap, channel, eventLoop.
bootstrap 主要负责服务建⽴与发布 ;
channel 主要负责协议建⽴与协议事件处理 ;
eventloop 主要负责任务执⾏与事件监听;
在基于 TCP 的 socket 程序⾥⾯, 我们的协议主要是指⼀个 socket 的建⽴, listen, accept, connect, read, write 等。
netty 使⽤协议与逻辑分离的思想, 允许我们通过接⼝来实现, 当协议事件发⽣时, 我们改如何处理我们的逻辑。
在Netty中,Selector(或者Reactor) 称作EventLoop,在Netty中采⽤的是单bossEventLoop+多workEventLoop的模式,
由bossEventLoop负责响应client的连接请求,并建⽴连接,由多个workEventLoop负责维护客户端socket的数据交互和读写⼯作,每个EventLoop都会在⼀个独⽴的线程中执⾏。。
什么是Netty?
以上是摘⾃这本书,本⽂的内容也是本⼈读了这本书之后的⼀些整理⼼得,如有不当之处欢迎⼤虾们指正
Netty和Tomcat有什么区别?
Netty和Tomcat最⼤的区别就在于通信协议,Tomcat是基于Http协议的,他的实质是⼀个基于http协议
的web容器,但是Netty不⼀样,他能通过编程⾃定义各种协议,因为netty能够通过codec⾃⼰来编码/解码字节流,完成类似redis访问的功能,这就是netty和tomcat最⼤的不同。
有⼈说netty的性能就⼀定⽐tomcat性能⾼,其实不然,tomcat从6.x开始就⽀持了nio模式,并且后续还有APR模式——⼀种通过jni调⽤apache⽹络库的模式,相⽐于旧的bio模式,并发性能得到了很⼤提⾼,特别是APR模式,⽽netty是否⽐tomcat性能更⾼,则要取决于netty程序作者的技术实⼒了。
为什么Netty受欢迎?
如第⼀部分所述,netty是⼀款收到⼤公司青睐的框架,在我看来,netty能够受到青睐的原因有三:
1. 并发⾼
2. 传输快
3. 封装好
Netty为什么并发⾼
Netty是⼀款基于NIO(Nonblocking I/O,⾮阻塞IO)开发的⽹络通信框架,对⽐于BIO(Blocking I/O,阻塞IO),他的并发性能得到了很⼤提⾼,两张图让你了解BIO和NIO的区别:
阻塞IO的通信⽅式
⾮阻塞IO的通信⽅式
从这两图可以看出,NIO的单线程能处理连接的数量⽐BIO要⾼出很多,⽽为什么单线程能处理更多的
连接呢?原因就是图⼆中出现
的Selector。
当⼀个连接建⽴之后,他有两个步骤要做,第⼀步是接收完客户端发过来的全部数据,第⼆步是服务端处理完请求业务之后返回response 给客户端。NIO和BIO的区别主要是在第⼀步。
在BIO中,等待客户端发数据这个过程是阻塞的,这样就造成了⼀个线程只能处理⼀个请求的情况,⽽机器能⽀持的最⼤线程数是有限的,这就是为什么BIO不能⽀持⾼并发的原因。
⽽NIO中,当⼀个Socket建⽴好之后,Thread并不会阻塞去接受这个Socket,⽽是将这个请求交给Selector,Selector会不断的去遍历所有的Socket,⼀旦有⼀个Socket建⽴完成,他会通知Thread,然后Thread处理完数据再返回给客户端——这个过程是不阻塞的,这样就能让⼀个Thread处理更多的请求了。
下⾯两张图是基于BIO的处理流程和netty的处理流程,辅助你理解两种⽅式的差别:
BIO的处理流程
NIO的处理流程
除了BIO和NIO之外,还有⼀些其他的IO模型,下⾯这张图就表⽰了五种IO模型的处理流程:
BIO,同步阻塞IO,阻塞整个步骤,如果连接少,他的延迟是最低的,因为⼀个线程只处理⼀个连接,适⽤于少连接且延迟低的场景,⽐如说数据库连接。
NIO,同步⾮阻塞IO,阻塞业务处理但不阻塞数据接收,适⽤于⾼并发且处理简单的场景,⽐如聊天软件。
多路复⽤IO,他的两个步骤处理是分开的,也就是说,⼀个连接可能他的数据接收是线程a完成的,数据处理是线程b完成的,他⽐BIO 能处理更多请求。
信号驱动IO,这种IO模型主要⽤在嵌⼊式开发,不参与讨论。
异步IO,他的数据请求和数据处理都是异步的,数据请求⼀次返回⼀次,适⽤于长连接的业务场景。
以上摘⾃
Netty为什么传输快
Netty的传输快其实也是依赖了NIO的⼀个特性——零拷贝。我们知道,Java的内存有堆内存、栈内存和字符串常量池等等,其中堆内存是占⽤内存空间最⼤的⼀块,也是Java对象存放的地⽅,⼀般我们的数据如果需要从IO读取到堆内存,中间需要经过Socket缓冲区,也就是说⼀个数据会被拷贝两次才能到达他的的终点,如果数据量⼤,就会造成不必要的资源浪费。
Netty针对这种情况,使⽤了NIO中的另⼀⼤特性——零拷贝,当他需要接收数据的时候,他会在堆内存之外开辟⼀块内存,数据就直接从IO读到了那块内存中去,在netty⾥⾯通过ByteBuf可以直接对这些数据进⾏直接操作,从⽽加快了传输速度。
下两图就介绍了两种拷贝⽅式的区别,摘⾃
传统数据拷贝
零拷贝
上⽂介绍的ByteBuf是Netty的⼀个重要概念,他是netty数据处理的容器,也是Netty封装好的⼀个重要体现,将在下⼀部分做详细介绍。
阻塞I/O
public class PlainOioServer {
public void serve(int port) throws IOException {
final ServerSocket socket = new ServerSocket(port); //1
try {
for (;;) {
final Socket clientSocket = socket.accept(); //2
System.out.println("Accepted connection from " + clientSocket);
new Thread(new Runnable() { //3
@Override
public void run() {
OutputStream out;
try {
out = OutputStream();
out.write("Hi!\r\n".getBytes(Charset.forName("UTF-8"))); //4 out.flush();
clientSocket.close(); //5
} catch (IOException e) {
e.printStackTrace();
try {
clientSocket.close();
} catch (IOException ex) {
// ignore on close
}
}
}
}).start(); //6
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
⾮阻塞IO
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论