> For the complete documentation index, see [llms.txt](https://ldbmcs.gitbook.io/java/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ldbmcs.gitbook.io/java/java-2/java-io-and-nio-and-aio/java-io-netty.md).

# Java N(A)IO - Netty

> 原文链接：[Java N(A)IO - Netty](https://www.pdai.tech/md/java/io/java-io-nio-netty.html)

> Netty是一个高性能、异步事件驱动的NIO框架，提供了对TCP、UDP和文件传输的支持。作为当前最流行的NIO框架，Netty在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用，一些业界著名的开源组件也基于Netty构建，比如RPC框架、zookeeper等。@pdai

## 1. NIO框架

目前流行的NIO框架非常的多。在论坛上、互联网上大家讨论和使用最多的有以下几种:

* 原生JAVA NIO框架:

  JAVA NIO通信框架基于多路复用IO原理，我们将详细讲解它的工作原理。
* APACHE MINA 2:

  是一个网络应用程序框架，用来帮助用户简单地开发高性能和高可扩展性的网络应用程序。它提供了一个通过Java NIO在不同的传输例如TCP/IP和UDP/IP上抽象的事件驱动的异步API。
* NETTY 4/5:

  Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具，用以快速开发高性能、高可靠性的网络服务器和客户端程序。我们将讲解NETTY 4 的工作原理。另外说一句: MINA和NETTY的主要作者是同一人Trustin Lee。
* Grizzly:

  Grizzly是一种应用程序框架，专门解决编写成千上万用户访问服务器时候产生的各种问题。使用JAVA NIO作为基础，并隐藏其编程的复杂性。

## 2. 比较好的基于NIO的开源框架(Netty)

### 2.1 优点

* api简单，开发门槛低
* 功能强大，内置了多种编码、解码功能
* 与其它业界主流的NIO框架对比，netty的综合性能最优
* 社区活跃，使用广泛，经历过很多商业应用项目的考验
* 定制能力强，可以对框架进行灵活的扩展

### 2.2 例子

```xml
<dependency>
     <groupId>org.jboss.netty</groupId>
     <artifactId>netty</artifactId>
     <version>3.2.5.Final</version>
</dependency>
```

* 服务端。接收客户端请求并将内容打印出来，同时发送一个消息收到回执。

  ```java
  public class NettyServer {

      private static int HEADER_LENGTH = 4;

      public void bind(int port) throws Exception {

          ServerBootstrap b = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(),
                                                                                    Executors.newCachedThreadPool()));

          // 构造对应的pipeline
          b.setPipelineFactory(new ChannelPipelineFactory() {

              public ChannelPipeline getPipeline() throws Exception {
                  ChannelPipeline pipelines = Channels.pipeline();
                  pipelines.addLast(MessageHandler.class.getName(), new MessageHandler());
                  return pipelines;
              }
          });
          // 监听端口号
          b.bind(new InetSocketAddress(port));
      }

      // 处理消息
      static class MessageHandler extends SimpleChannelHandler {

          public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
              // 接收客户端请求
              ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
              String message = new String(buffer.readBytes(buffer.readableBytes()).array(), "UTF-8");
              System.out.println("<服务端>收到内容=" + message);

              // 给客户端发送回执
              byte[] body = "服务端已收到".getBytes();
              byte[] header = ByteBuffer.allocate(HEADER_LENGTH).order(ByteOrder.BIG_ENDIAN).putInt(body.length).array();
              Channels.write(ctx.getChannel(), ChannelBuffers.wrappedBuffer(header, body));
              System.out.println("<服务端>发送回执,time=" + System.currentTimeMillis());

          }
      }

      public static void main(String[] args) {
          try {
              new NettyServer().bind(1088);
          } catch (Exception e) {
              e.printStackTrace();
          }
          ;
      }
  }
  ```
* 客户端。向服务端发送一个请求，然后打印服务端响应的内容。

  ```java
  public class NettyClient {

      private final ByteBuffer readHeader  = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
      private final ByteBuffer writeHeader = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
      private SocketChannel    channel;

      public void sendMessage(byte[] body) throws Exception {
          // 创建客户端通道
          channel = SocketChannel.open();
          channel.socket().setSoTimeout(60000);
          channel.connect(new InetSocketAddress(AddressUtils.getHostIp(), 1088));

          // 客户端发请求
          writeWithHeader(channel, body);

          // 接收服务端响应的信息
          readHeader.clear();
          read(channel, readHeader);
          int bodyLen = readHeader.getInt(0);
          ByteBuffer bodyBuf = ByteBuffer.allocate(bodyLen).order(ByteOrder.BIG_ENDIAN);
          read(channel, bodyBuf);
          System.out.println("<客户端>收到响应内容: " + new String(bodyBuf.array(), "UTF-8") + ",长度:" + bodyLen);
      }

      private void writeWithHeader(SocketChannel channel, byte[] body) throws IOException {
          writeHeader.clear();
          writeHeader.putInt(body.length);
          writeHeader.flip();
          // channel.write(writeHeader);
          channel.write(ByteBuffer.wrap(body));
      }

      private void read(SocketChannel channel, ByteBuffer buffer) throws IOException {
          while (buffer.hasRemaining()) {
              int r = channel.read(buffer);
              if (r == -1) {
                  throw new IOException("end of stream when reading header");
              }
          }
      }

      public static void main(String[] args) {
          String body = "客户发的测试请求！";
          try {
              new NettyClient().sendMessage(body.getBytes());
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
  }
  ```

## 2. 参考文章

* <https://blog.csdn.net/yinwenjie/article/details/48829419>
* <https://blog.csdn.net/yinwenjie/article/details/48969853>
* [Netty入门简介](https://mp.weixin.qq.com/s/RPTETiULRAkOS-ZTd6xM2A)
