近日在学习netty,却发现没那么容易上手,专研了几天后算是弄清楚了netty到底是干什么的,所看资料比较多,此文章便把这些资料与我的思考做一个总结帮助大家更好入门。
要更好理解netty首先要了解以下一些前置知识
- Blocking I/O ,请看以下Java 网络编程的一段代码
public class PlainOioServer {
public void serve(int port) throws IOException {
final ServerSocket socket = new ServerSocket(port);
try {
for (;;) {
//accept一直阻塞直到获取一个客户端,所谓阻塞就是不执行后面代码,不阻塞就是继续执行后续代码
final Socket clientSocket = socket.accept();
System.out.println(
"Accepted connection from " + clientSocket);
//创建一个新的Thread处理
new Thread(new Runnable() {
@Override
public void run() {
OutputStream out;
try {
out = clientSocket.getOutputStream();
out.write("Hi!\r\n".getBytes(
Charset.forName("UTF-8")));
out.flush();
clientSocket.close();
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
clientSocket.close();
}
catch (IOException ex) {
// ignore on close
}
}
}
}).start();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
当请求很多的时候会为每一个请求创建一个线程,每一个线程都会分配一定的内存,而且这些线程都会阻塞,导致资源利用率低下,这样的设计一定满足不了高并发。
-
Non-blocking I/O ,为了满足多个请求Java引入了NIO包进行编程,这里得引入几个名词
回调(Callback):A方法里有B方法的一个引用,当B方法完成某一条件后可以通知A方法 事件驱动(Event-driven):当一个事件放生时,可以在任何时间响应这个事件
具体代码就不贴了了,涉及很多类看着头晕,网上也有很多解析,对着下面一张图我说一下原理
对于每一个socket,就对应一个Channel,每个Channel会到Selector注册,当某一个Channel状态改变的时候,就会触发响应的事件,然后根据事件的类型去执行相应的动作。Channel状态改变会通知selector,这就是上面指的回调,根据发生事件的类型去执行任务就是所谓的事件驱动,流程算是清楚了,但是为什么这么做呢,这一点我再好好解释。
典型的后端服务分为通信层和业务逻辑层,通信层通常连接数很多(用户大部分时间实在浏览而非点击),收发数据是慢速I/O。传统方式做的话每个请求分配线程,而且线程常常因为等待I/O阻塞,且不同线程间频繁切换,这都是很浪费资源的。多线程的好处就是当一个线程阻塞时,另一个线程可以继续执行任务,而这种模式下大部分线程都会因I/O而阻塞。怎么令线程不阻塞呢,我们就要使用异步回调的方式,用一个线程去管理这些请求的状态,当某个请求数据准备好了就去调用它,没准备好就操作下一个请求,这就是上面的selector。
Netty的产生原因是使Java NIO的编程更容易。
Netty
定义:一个异步事件驱动的网络应用框架,帮助快速开发高性能的客户端与服务端。
上面是Netty的一张架构图。
每一个Channel(一个客户端请求)注册一个EventLoop,这个EventLoop会处理这个请求的I/O事件直到这个请求结束。
未完待续。。。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。