【Netty第一章】 Netty介绍

Netty介绍

Netty是基于Java NIO的网络应用框架,是一个NIO Client-Server(客户端服务器)框架,使用Netty可以快速开发网络应用,例如服务器和客户端协议。Netty是完全基于NIO实现的,所以整个Netty都是异步的。

1.1 为什么使用Netty

David John Wheeler说过”在计算机科学中的所有问题都可以通过间接的方法解决“。作为一个NIO Client-Server框架,Netty提供了这样一个间接的解决方法。Netty提供了高层次的抽象来简化TCP和UDP服务器的变成,但是你仍然可以使用底层的API。

1.1.1 并不是所有的网络框架都是一样的

Netty的”quick and easy(高性能和简单易用)“并不意味着编写的程序的性能和可维护性会受到影响。从Netty中实现的协议如FTP,SMTP,HTTP,WebSocket,SPDY以及各种二进制和基于文本的传统协议中获得的经验导致Netty的创始人姚非常小心的设计。Netty成功的提供了易于开发,高性能和高稳定性,以及较强的扩展性。

1.1.2 Netty的功能非常丰富

下图是Netty框架的组成
image

1.2 异步设计

整个Netty的API都是异步的。
对于网络应用来说,IO一般是性能的瓶颈,使用异步IO可以较大程度上提高程序性能,因为异步变得越来越重要。
异步处理提倡更有效的使用资源,它允许你创建一个任务,当有事件发生时将获得通知并等待事件完成,这样就不会阻塞,不管事件完成与否都会及时返回,资源利用率更高,程序可以利用剩余的资源做一些其他的事情。

1.2.1 Callbacks(回调)

回调一般是异步处理的一种技术。一个回调是被传递到并且执行完该方法。

package com.example.netty;

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 com.example.netty;

public interface Fetcher {
    void fetchData(FetcherCallback callback);
}
package com.example.netty;

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 com.example.netty;

public interface FetcherCallback {

    void onData(Data data) throws Exception;
    void onError(Throwable cause);
}
package com.example.netty;

public class Data {

    private int n;
    private int m;

    public Data(int n, int m){
        this.n = n;
        this.m = m;
    }

    public int getN() {
        return n;
    }

    public void setN(int n) {
        this.n = n;
    }

    public int getM() {
        return m;
    }

    public void setM(int m) {
        this.m = m;
    }

    @Override
    public String toString() {
        int r = n/m;
        return n + "/" + m + " = " + r;
    }
}

上面的例子只是一个简单的模拟回调,Fetcher.fetcherData()方法需传递一个FetcherCallback类型的参数,当获得数据或发生错误时被回调
FetcherCallback.onData(),将接受数据时被调用
FetcherCallback.onError(),发生错误时被调用

1.2.2 Futures

第二种技术是使用Futurwes,Futures是一个抽象的概念,它表示一个值,该值可能在没一点变得可用。一个Future要么获得计算完的结果,要么获得计算失败后的一场。Java在java.util.concurrent保重附带了Future接口,它使用Execitor异步执行。例如下面的代码,每传递一个Runnable对象到ExecutorService.submit()方法就会得到一个回调的Future,你能使用它检测是否执行完成。

package com.example.netty;

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;
        }
    }

}

1.3 Java中的Blocking和non-blocking IO对比

1.4 NIO的问题和Netty中是如何解决这些问题的

1.4.1 跨平台和兼容性问题

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就可以轻
松实现相关功能。

1.4.2 扩展ByteBuffer

ByteBuffer是一个数据容器,但是可惜的是JDK没有开发ByteBuffer实现的源码;ByteBuffer允许包装一个byte[]来获得一个实例,如果你希望尽量减少内存拷贝,那么这种方式是非常有用的。若果你想将ByteBuffer重新实现,那么不要浪费你的时间了,ByteBuffer的构造函数是私有的,所以它不能被扩展。Netty提供了自己的ByteBuffer实现,Netty通过一些简单的APIs对ByteBuffer进行构造、使用和操作,以此来解决NIO中的一些限制。

1.4.3 NIO对缓冲区的聚合和分散操作可能会操作内存泄露

很多Channel的实现支持Gather和Scatter。这个功能允许从从多个ByteBuffer中读入或写入到过个ByteBuffer,这样做可以提供性能。操作系统底层知道如何处理这些被写入/读出,并且能以最有效的方式处理。如果要分割的数据再多个不同的ByteBuffer中,使用Gather/Scatter是比较好的方式。
例如,你可能希望header在一个ByteBuffer中,而body在另外的ByteBuffer中;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值