Netty学习--Netty简介

一.JavaApi处理方式

  •  ServerSocket serverSocket = new ServerSocket(portNumber);
     Socket clientSocket = serverSocket.accept();
     BufferedReader in = new BufferedReader(
     new InputStreamReader(clientSocket.getInputStream()));
     PrintWriter out =new PrintWriter(clientSocket.getOutputStream(), true);
     String request, response;
     while ((request = in.readLine()) != null) {
         if ("Done".equals(request)) {
            break;
     }
    response = processRequest(request);
    out.println(response);
    
代码清单1-1 实现了Socket API 的基本模式之一。以下是最重要的几点。

1.ServerSocket 上的accept()方法将会一直阻塞到一个连接建立,随后返回一个新的Socket 用于客户端和服务器之间的通信。该ServerSocket 将继续监听传入的连接。
2.BufferedReader 和PrintWriter 都衍生自Socket 的输入输出流。前者从一个字符输入流中读取文本,后者打印对象的格式化的表示到文本输出流。
3.readLine()方法将会阻塞,直到在处一个由换行符或者回车符结尾的字符串被读取。
4.客户端的请求已经被处理。


Netty学习--Netty简介_第1张图片
使用阻塞I/O 处理多个连接

二.非阻塞NIO

Netty学习--Netty简介_第2张图片
使用Selector 的非阻塞I/O
1).selector选择器

class java.nio.channels.Selector 是Java 的非阻塞I/O 实现的关键。它使用了事件通知API以确定在一组非阻塞套接字中有哪些已经就绪能够进行I/O 相关的操作。因为可以在任何的时间检查任意的读操作或者写操作的完成状态,所以如图所示,一个单一的线程便可以处理多个并发的连接。

三.Netty 的核心组件

1) Channel

它代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一个或者多个不同的I/O操作的程序组件)的开放连接,如读操作和写操作。

2) 回调

一个回调其实就是一个方法,一个指向已经被提供给另外一个方法的方法的引用。这使得后者可以在适当的时候调用前者。回调在广泛的编程场景中都有应用,而且也是在操作完成后通知相关方最常见的方式之一。

3) Future

Future 提供了另一种在操作完成时通知应用程序的方式。这个对象可以看作是一个异步操作的结果的占位符;它将在未来的某个时刻完成,并提供对其结果的访问。
Netty的ChannelFuture提供了几种额外的方法,这些方法使得我们能够注册一个或ChannelFutureListener实例。监听器的回调方法operationComplete(),将会在对应的操作完成时被调用。然后监听器可以判断该操作是成功地完成了还是出错了。如果是后者,我们可以检索产生的Throwable。简而言之,由ChannelFutureListener提供的通知机制消除了手动检查对应的操作是否完成的必要。

       Channel channel = ...;
       // Does not block
       ChannelFuture future = channel.connect(
       new InetSocketAddress("192.168.0.1", 25));
       future.addListener(new ChannelFutureListener() {
       @Override
       public void operationComplete(ChannelFuture future) {
         if (future.isSuccess()){
           ByteBuf buffer = Unpooled.copiedBuffer(
           "Hello",Charset.defaultCharset());
           ChannelFuture wf = future.channel().writeAndFlush(buffer);
           ....
         } else {
           Throwable cause = future.cause();
           cause.printStackTrace();
          }
       }
      });
4) 事件和ChannelHandler

每个事件都可以被分发给ChannelHandler 类中的某个用户实现的方法。这是一个很好的将事件驱动范式直接转换为应用程序构件块的例子。图1-3 展示了一个事件是如何被一个这样的ChannelHandler 链处理的。


Netty学习--Netty简介_第3张图片
图1-3 流经ChannelHandler 链的入站事件和出站事件
5) 总结

①Future、回调和ChannelHandler
Netty 的异步编程模型是建立在Future 和回调的概念之上的, 而将事件派发到ChannelHandler的方法则发生在更深的层次上。结合在一起,这些元素就提供了一个处理环境,使你的应用程序逻辑可以独立于任何网络操作相关的顾虑而独立地演变。这也是Netty 的设计方式的一个关键目标。拦截操作以及高速地转换入站数据和出站数据,都只需要你提供回调或者利用操作所返回的Future。这使得链接操作变得既简单又高效,并且促进了可重用的通用代码的编写。
②选择器、事件和EventLoop
Netty 通过触发事件将Selector 从应用程序中抽象出来,消除了所有本来将需要手动编写的派发代码。在内部,将会为每个Channel 分配一个EventLoop,用以处理所有事件,包括:

  • 1.注册感兴趣的事件;
  • 2.将事件派发给ChannelHandler;
  • 3.安排进一步的动作。

EventLoop 本身只由一个线程驱动,其处理了一个Channel 的所有I/O 事件,并且在该EventLoop 的整个生命周期内都不会改变。这个简单而强大的设计消除了你可能有的在ChannelHandler 实现中需要进行同步的任何顾虑,因此,你可以专注于提供正确的逻辑,用来在有感兴趣的数据要处理的时候执行。如同我们在详细探讨Netty 的线程模型时将会看到的,该API 是简单而紧凑的。

6)为什么使用netty
  • netty 底层基于 jdk 的 NIO ,我们为什么不直接基于 jdk 的 nio 或者其他 nio 框架?
    1.使用 jdk 自带的 nio 需要了解太多的概念,编程复杂
    2.netty 底层 IO 模型随意切换,而这一切只需要做微小的改动
    3.netty 自带的拆包解包,异常检测等机制让你从nio的繁重细节中脱离出来,让你只需要关心业务逻辑
    4.netty 解决了 jdk 的很多包括空轮训在内的 bug
    5.netty 底层对线程,selector 做了很多细小的优化,精心设计的 reactor 线程做到非常高效的并发处理
    6.自带各种协议栈让你处理任何一种通用协议都几乎不用亲自动手
    7.netty 社区活跃,遇到问题随时邮件列表或者 issue
    8.netty 已经历各大rpc框架,消息中间件,分布式通信中间件线上的广泛验证,健壮性无比强大

你可能感兴趣的:(Netty学习--Netty简介)