Netty
是基于
Java NIO
的网络应用框架,Netty是一个NIO client-server(客户端服务器)框架,使用Netty可以快速开发网络应用,例如服务器和客户端协议。Netty提
供了一种新的方式来使开发网络应用程序,这种新的方式使得它很容易使用和有很强的扩展性。Netty的内部实现时很复杂的,但是Netty提供了简单易用的api从网络处理代码中解耦业务逻辑。Netty是完全基于NIO实现的,所以整个Netty都是异步的。
”作为一个NIO client-server框架,Netty提供了这样的一个间接的解决方法。Netty提供了高层次的抽象来简化TCP和UDP服务器的编程,但是你仍然可以使用底层地API。
Netty框架的组成
Netty除了提供传输和协议,在其他各领域都有发展。Netty为开发者提供了一套完整的工具,看下面表格:
Development Area | Netty Features |
Design(设计) | 各种传输类型,阻塞和非阻塞套接字统一的API 使用灵活 简单但功能强大的线程模型 无连接的DatagramSocket支持 链逻辑,易于重用 |
Ease of Use(易于使 用) | 提供大量的文档和例子 除了依赖jdk1.6+,没有额外的依赖关系。某些功能依赖jdk1.7+,其他特性可能有相 关依赖,但都是可选的。 |
Performance(性能) | 比Java APIS更好的吞吐量和更低的延迟 因为线程池和重用所有消耗较少的资源 尽量减少不必要的内存拷贝 |
Robustness(鲁棒性) | 鲁棒性,可以理解为健壮性 链接快或慢或超载不会导致更多的OutOfMemoryError 在高速的网络程序中不会有不公平的read/write |
Security(安全性) | 完整的SSL/TLS和StartTLS支持 可以在如Applet或OSGI这些受限制的环境中运行 |
Community(社区) | 版本发布频繁 社区活跃 |
整个
Netty
的
API
都是异步的,异步处理不是一个新的机制,这个机制出来已经有一些时间了。对网络应用来说,
IO
一般是性
能的瓶颈,使用异步
IO
可以较大程度上提高程序性能,因为异步变的越来越重要。
异步处理提倡更有效的使用资源,它允许你创建一个任务,当有事件发生时将获得通知并等待事件完成。这样就不会阻塞,不管事件完成与否都会及时返回,资源利用率更高,程序可以利用剩余的资源做一些其他的事情。
NIO是一个比较底层的APIs,它依赖于操作系统的IO APIs。Java实现了统一的接口来操作IO,其在所有操作系统中的工作行为是一样的。使用NIO会经常发现代码在Linux上正常运行,但在Windows上就会出现问题。建议如果使用NIO编写程序,就应该在所有的操作系统上进行测试来支持,使程序可以在任何操作系统上正常运行;即使在所有的Linux系统上都测试通过了,也要在其他的操作系统上进行测试;若不验证,以后就可能会出问题。NIO2看起来很理想,但是NIO2只支持Jdk1.7+,若程序在Java1.6上运行,则无法使用NIO2。另外,Java7的NIO2中没有提供DatagramSocket的支持,所以NIO2只支持TCP程序,不支持UDP程序。Netty提供一个统一的接口,同一语义无论在Java6还是Java7的环境下都是可以运行的,开发者无需关心底层APIs就可以轻松实现相关功能。
java自带的NIO有两个版本,NIO版本1实现了非阻塞功能,JDK7之后出现NIO2,增加了异步功能和一些文件操作的api,但是无论NIO版本1和2都是有缺陷的,比如平台不兼容,ByteBuf扩展性差等,后来就出现了netty,netty对NIO进行了一下封装和优化设计,让我们用它提供的简单api就可以些出性能强大的服务器,但是踪其底层,都是一样的
回调一般是异步处理的一种技术。一个回调是被传递到并且执行完该方法。
代码:
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;
}
}
第二种技术是使用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;
}
}
}