
本章介绍
- Netty介绍
- 为什么要使用non-blocking IO(NIO)
- 堵塞IO(blocking IO)和非堵塞IO(non-blocking IO)对照
- Java NIO的问题和在Netty中的解决方式
Netty是基于Java NIO的网络应用框架,假设你是Java网络方面的新手,那么本章将是你学习Java网络应用的開始;对于有经验的开发人员来说,学习本章内容也是非常好的复习。假设你熟悉NIO和NIO2,你能够随时跳过本章直接从第二章開始学习。在你的机器上执行第二章编写的Nettyserver和client。
Netty是一个NIO client-server(clientserver)框架,使用Netty能够高速开发网络应用,比如server和client协议。Netty提供了一种新的方式来使开发网络应用程序,这样的新的方式使得它非常easy使用和有非常强的扩展性。Netty的内部实现时非常复杂的,可是Netty提供了简单易用的api从网络处理代码中解耦业务逻辑。Netty是全然基于NIO实现的,所以整个Netty都是异步的。
网络应用程序通常须要有较高的可扩展性,不管是Netty还是其它的基于Java NIO的框架,都会提供可扩展性的解决方式。Netty中一个关键组成部分是它的异步特性,本章将讨论同步(堵塞)和异步(非堵塞)的IO来说明为什么使用异步代码来解决扩展性问题以及怎样使用异步。
对于那些初学网络变成的读者,本章将帮助您对网络应用的理解,以及Netty是怎样实现他们的。它说明了怎样使用主要的Java网络API,探讨Java网络API的长处和缺点并阐述Netty是怎样解决Java中的问题的,比方Eploo错误或内存泄露问题。
在本章的结尾,你会明确什么是Netty以及Netty提供了什么,你会理解Java NIO和异步处理机制,并通过本书的其它章节加强理解。
1.1 为什么使用Netty?
1.1.1 不是全部的网络框架都是一样的
Choice Award(Duke's Choice奖)。
1.1.2 Netty的功能很丰富

Development Area | Netty Features |
Design(设计) |
|
Ease of Use(易于使用) |
|
Performance(性能) |
|
Robustness(鲁棒性) | 鲁棒性,能够理解为健壮性
|
Security(安全性) |
|
Community(社区) |
|
除了列出的功能外,Netty为Java NIO中的bug和限制也提供了解决方式。我们须要深刻理解Netty的功能以及它的异步处理机制和它的架构。NIO和Netty都大量使用了异步代码,而且封装的非常好,我们无需了解底层的事件选择机制。以下我们来看看为什么须要异步APIS。
1.2 异步设计
1.2.1 Callbacks(回调)
package netty.in.action; public class Worker { public void doWork() {
Fetcher fetcher = new MyFetcher(new Data(1, 0));
fetcher.fetchData(new FetcherCallback() {
@Override
public void onError(Throwable cause) {
System.out.println("An error accour: " + cause.getMessage());
} @Override
public void onData(Data data) {
System.out.println("Data received: " + data);
}
});
} public static void main(String[] args) {
Worker w = new Worker();
w.doWork();
} }
package netty.in.action; public interface Fetcher {
void fetchData(FetcherCallback callback);
}
package netty.in.action; public class MyFetcher implements Fetcher { final Data data; public MyFetcher(Data data){
this.data = data;
} @Override
public void fetchData(FetcherCallback callback) {
try {
callback.onData(data);
} catch (Exception e) {
callback.onError(e);
}
} }
package netty.in.action; public interface FetcherCallback {
void onData(Data data) throws Exception;
void onError(Throwable cause);
}
package netty.in.action; public class Data { private int n;
private int m; public Data(int n,int m){
this.n = n;
this.m = m;
} @Override
public String toString() {
int r = n/m;
return n + "/" + m +" = " + r;
}
}
上面的样例仅仅是一个简单的模拟回调,要明确其所表达的含义。Fetcher.fetchData()方法需传递一个FetcherCallback类型的參数,当获得数据或错误发生时被回调。对于每种情况都提供了允许的方法:
- FetcherCallback.onData(),将接收数据时被调用
- FetcherCallback.onError(),错误发生时被调用
由于能够将这些方法的运行从"caller"线程移动到其它的线程运行;但也不会保证FetcherCallback的每一个方法都会被运行。回调过程有个问题就是当你使用链式调用
非常多不同的方法会导致线性代码;有些人觉得这样的链式调用方法会导致代码难以阅读,可是我觉得这是一种风格和习惯问题。比如,基于Javascript的Node.js越来越受欢迎,它使用了大量的回调,很多人都觉得它的这样的方式利于阅读和编写。
1.2.2 Futures
另外一种技术是使用Futures。Futures是一个抽象的概念,它表示一个值,该值可能在某一点变得可用。一个Future要么获得计算完的结果,要么获得计算失败后的异常。Java在java.util.concurrent包中附带了Future接口,它使用Executor异步运行。比如以下的代码,每传递一个Runnable对象到ExecutorService.submit()方法就会得到一个回调的Future,你能使用它检測是否运行完毕。
package netty.in.action; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; public class FutureExample { public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newCachedThreadPool();
Runnable task1 = new Runnable() {
@Override
public void run() {
//do something
System.out.println("i am task1.....");
}
};
Callable<Integer> task2 = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
//do something
return new Integer(100);
}
};
Future<?> f1 = executor.submit(task1);
Future<Integer> f2 = executor.submit(task2);
System.out.println("task1 is completed? " + f1.isDone());
System.out.println("task2 is completed? " + f2.isDone());
//waiting task1 completed
while(f1.isDone()){
System.out.println("task1 completed.");
break;
}
//waiting task2 completed
while(f2.isDone()){
System.out.println("return value by task2: " + f2.get());
break;
}
} }
有时候使用Future感觉非常丑陋,由于你须要间隔检查Future是否已完毕,而使用回调会直接收到返回通知。看完这两个经常使用的异步运行技术后,你可能想知道使用哪个最好?这里没有明白的答案。其实,Netty两者都使用,提供两全其美的方案。下一节将在JVM上首先使用堵塞,然后再使用NIO和NIO2写一个网络程序。这些是本书兴许章节不可缺少的基础知识,假设你熟悉Java网络AIPs,你能够高速翻阅就可以。
1.3 Java中的Blocking和non-blocking IO对照
本节主要解说Java的IO和NIO的差异,这里只是多赘述,网络已有非常多相关文章。
1.4 NIO的问题和Netty中是怎样解决这些问题的
1.4.1 跨平台和兼容性问题
1.4.2 扩展ByteBuffer
1.4.3 NIO对缓冲区的聚合和分散操作可能会操作内存泄露


1.4.4 Squashing the famous epoll bug
even today the "famous" epoll- bug can lead to an "invalid" state in the selector, resulting in 100% CPU-usage and spinning. The only way to recover is to recycle the old selector and transfer the previously registered Channel instances to
the newly created Selector.
which is in the Javadocs of the Selector.select() method:Selector.select() must not unblock if nothing is selected.
while (true) {
int selected = selector.select();
Set<SelectedKeys> readyKeys = selector.selectedKeys();
Iterator iterator = readyKeys.iterator();
while (iterator.hasNext()) {
...
...
}
}
...
while (true) {
}
...
work.
Netty addresses them for you.
1.5 Summary
of the reasons to use a non-blocking framework. You learned how to use the JDK API to write network code in both blocking and non-blocking modes. This included the new non-blocking API, which comes with JDK 7. After seeing the NIO APIs in action,
it was also important to understand some of the known issues that you may run into. In fact, this is why so many people use Netty: to take care of workarounds and other JVM quirks. In the next chapter, you'll learn the basics of the Netty API and programming
model, and, finally, use Netty to write some useful code.