工作数年还是对Netty还是知之甚少,虽然以前有过短暂的使用但未曾去做过了解,所以准备深入了解下Netty。从了解、使用到深入,逐步学习,先从了解开始。

Netty 是一个利用 Java 的高级网络的能力,隐藏了Java背后的复杂性然后提供了一个易于使用的 API 的客户端/服务器框架。

socket

在网络发展初期,需要花很多时间来学习socket的复杂,寻址等等,在socket库上进行编码,并需要在不同的操作系统上做不同的处理。如图:

java中使用netty中的udp java netty socket_java中使用netty中的udp

这些早期的 Java API(java.net)只能通过原生的 socket 库来支持所谓的“blocking(阻塞)”的功能。一个简单的例子:

// ServerSocket 创建并监听端口的连接请求
        ServerSocket serverSocket = new ServerSocket(portNumber);
        // accept() 调用阻塞,返回一个新的Socket用来处理客户端和服务端的交互
        Socket clientSocket = serverSocket.accept();
        // 流被创建用于处理socket的输入和输出数据。BufferedReader读取从字符输入流里面的文本。
        BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        // PrintWriter打印格式化展示的对象读到本文输出流
        PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
        String request, response;
        // 处理循环开始readLine()阻塞,读取字符串直到最后是换行或者输入终止
        while ((request = in.readLine()) != null) {
            // 如果客户端发送的是“Close”处理循环退出
            if ("Close".equals(request)) {
                break;
            }
        }
        // 执行方法处理请求,返回服务器的响应
        response = processRequest(request);
        // 响应发回客户端
        out.println(response);

可以看出,这段代码限制每次只能处理一个连接。为了实现多个并行的客户端我们需要分配一个新的Thread给每个新的客户端Socket。但考虑使用这种方法来支持大量的同步,长连接。在任何时间点多线程可能处于休眠状态,等待输入或输出数据。这很容易使得资源的大量浪费,对性能产生负面影响。

除了示例中所示阻塞调用,原生socket库同时也包含了非阻塞I/O的功能。这使我们能够确定任何一个socket中是否有数据准备读或写。我们还可以设置标志,因为读/写调用如果没有数据立即返回;就是说,如果一个阻塞被调用后就会一直阻塞,直到处理完成。通过这种方法,会带来更大的代码的复杂性成本,其实我们可以获得更多的控制权来如何利用网络资源。

JAVA NIO

在 2002 年,Java 1.4 引入了非阻塞 API 在 java.nio 包(NIO)即Nonblocking I/O (非阻塞 I/O)。如图:

java中使用netty中的udp java netty socket_非阻塞_02


Selector最终决定哪一组注册的socket准备执行I/O。正如我们之前所解释的那样,这I/O操作设置为非阻塞模式。通过通知,一个线程可以同时处理多个并发连接。一个 Selector 由一个线程通常处理,但具体实施可以使用多个线程。因此,每次读或写操作执行能立即检查完成。总体而言,该模型提供了比阻塞 I/O模型更好的资源使用,因为可以用较少的线程处理更多连接,这意味着更少的开销在内存和上下文切换上。当没有 I/O 处理时,线程可以被重定向到其他任务上。

综上,Netty 是一个基于NIO的客户、服务器端的编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发。