Netty是一款异步事件驱动的网络应用程序框架,支持快速的开发可维护的高性能的面向协议的服务器和客户端。在网络编程中,阻塞、非阻塞、同步、异步经常被提到。同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?

常见的I/O模型有如下几种:

我们举一个场景来说明上面各是什么意思:

周末我和宝宝逛街,中午饿了,我们准备去吃饭。周末人多,吃饭需要排队,我和宝宝有以下几种方案:

(1)阻塞:我和宝宝点完餐后,不知道什么时候能做好,只好坐在餐厅里面等,直到做好,然后吃完才离开。宝宝本想还和我一起逛街的,但是不知道饭能什么时候做好,只好和我一起在餐厅等,而不能去逛街,直到吃完饭才能去逛街,中间等待做饭的时间浪费掉了。这就是典型的阻塞。

(2)非阻塞:宝宝不甘心白白在这等,又想去逛商场,又担心饭好了。所以我们逛一会,回来询问服务员饭好了没有,来来回回好多次,饭都还没吃都快累死了啦。这就是非阻塞。需要不断的轮询,是否准备好了。

(3)多路复用:与第二个方案差不多,餐厅安装了电子屏幕用来显示点餐的状态,这样我和宝宝逛街一会,回来就不用去询问服务员了,直接看电子屏幕就可以了。这样每个人的餐是否好了,都直接看电子屏幕就可以了,这就是典型的IO多路复用,如select、poll、epoll。

(4)异步:宝宝不想逛街,又嫌餐厅太吵了,想好好休息一下。于是我们叫外卖,打个电话点餐,然后我和宝宝可以在家好好休息一下(此处忽略带宝宝回家的细节),饭好了送货员送到家里来。这就是典型的异步,只需要打个电话说一下,然后可以做自己的事情,饭好了就送来了。

所以阻塞非阻塞的区别在于:简单理解为需要做一件事能不能立即得到返回应答,如果不能立即获得应答,需要等待,那就阻塞了,否则就可以理解为非阻塞。

而其实同步和异步的区别:就是在线程在等待的过程中能不能去做另外的事情,如果是同步,则线程一直等待或者去轮询结果;如果是异步,线程直接返回,去做其他的工作,而本次I/O完成之后会主动通知线程完成。实际上同步与异步是针对应用程序与内核的交互而言的。同步过程中进程触发IO操作并等待或者轮询的去查看IO操作是否完成。异步过程中进程触发IO操作以后,直接返回,做自己的事情,IO交给内核来处理,完成后内核通知进程IO完成。

其实我们经常用的ajax就是异步的JavaScriptXML技术,在jquery中我们可以配置async: false属性设置ajax为同步请求,其实在js处理处理ajax的时候,会开启单独的ajax工作线程来处理请求,随后,主线程就去做其他的事情了,在主线程收到该请求的回调通知的时候,他才会回来处理该请求结果。

下面两幅图展示了java网络编程中的阻塞I/O和java nio提供的非阻塞I/O的模型:

使用阻塞I/O处理多个连接                             使用selector的非阻塞I/O

使用selector的模型有如下的好处:

(1)较少的线程处理许多连接,减少内存管理和上下文切换带来的开销。

(2)没有I/O需要处理的时候,线程也可以被用于其他任务。

介绍完这些概念,我们来看一下netty有哪些核心构件吧。

1.channel

channel是java NIO的一个基本构造,代表着一个到实体的开发连接,如读操作和写操作。Channel通道和流非常相似,主要有以下几点区别:

  • 通道可以读也可以写,流一般来说是单向的(只能读或者写)。
  • 通道可以异步读写。
  • 通道总是基于缓冲区Buffer来读写。

在java中channel有如下的实现:

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel

FileChannel用于文件的数据读写。 DatagramChannel用于UDP的数据读写。 SocketChannel用于TCP的数据读写。 ServerSocketChannel允许我们监听TCP链接请求,每个请求会创建会一个SocketChannel.所以ServerSocketChannel并不传输数据。

2.回调

一个回调其实就是一个方法。在netty内部使用了回调来处理事件,当一个回调被触发,相关的事件可以被ChannelHandler的实现处理。

3.Future

Future提供了另一种在操作完成时通知应用程序的方式,它提供了对此次异步操作的的结果的访问。在java的concurrent包下的 Future只允许手动的检查对应的操作是否已经完成,或者一直阻塞到它完成,所以netty提供了它的实现-channelFuture用于在执行异步的时候调用。channelFuture还提供了额外的方法这些方法使得我们能够注册一个或者多个channelFutureListener 实例,这些监听器的回调方法:operationComplete(),将会在对应的操作完成时被调用每个netty的出站I/O操作都会返回一个ChannelFuture,如下代码中connect ()方法将会直接返回,不会阻塞。

 Channel channel = ...;
ChannelFuture future = channel.connect(new InetSocketAddress("192.168.0.1",25)); //异步的连接到远程节点

下面的例子展示了ChannelFuture和回调的用法:

 Channel channel = ...;
ChannelFuture future = channel.connect(new InetSocketAddress("192.168.9.1",25)); //异步连接到远程节点
future.addListener(new ChannelFutureListener(){ //注册一个ChannelFutureListener,以便在操作完成时获得通知
@Override
public void operationComplete(ChannelFuture future){
if(future.isSuccess()){ //如果操作是成功的,执行相应的操作
//... }else{
Throwable cause = future.cause(); //操作失败的异常处理
cause.printStackTrace();
}
}
});

其实可以把ChannelFutureListener看作是回调的一个更加精细的版本。回调和ChannelFutureListener相互补充,构成netty最为关键的组件之一。

4.事件和channelHandler

netty使用不同的事件开通知我们状态的改变或者是操作的状态,可能由入站数据或者相关的状态更改而触发的事件包括:

(1)连接激活或者连接失活

(2)数据读取

(3)用户事件

(4)错误事件

出站事件是未来将会触发的某个动作的操作结果,这些动作包括:

(1)打开或者关闭到远程节点的连接。

(2)将数据写到或者冲刷到套接字。

每个事件都可以被分发到ChannelHandler类中的某个用户实现的方法,下图展示了ChannelHandler链是怎么处理入站事件的(出站事件也是一样的):

netty的ChannelHandler为处理器提供了基本的抽象,netty也提供了大量的预定义的可以开箱即用的ChannelHandler 实现,包括用于各种协议的(如http或ssl/tls)的 ChannelHandler,在内部,ChannelHandler自己也使用了事件和future。

5.总结

netty通过触发事件将selector从应用程序抽象出来,消除了所有本来将需手动编写的派发代码,在内部,将会为每个Channel分配一个EventLoop,用于处理所有的事件,包括:

(1)注册感兴趣的事件

(2)将事件派发给ChannelHandler

(3)安排进一步的动作

EventLoop本身只由一个线程驱动,其处理了一个channel的所有的I/O事件,并且在该channel整个生命周期内都不会变,这种设计消除了可以在你的ChannelHandler中需要进行同步的顾虑。

下一节我们将深入的探讨netty的API和编程模型的基本知识。

一起来读Netty In Action(一)的更多相关文章

  1. 一起来读Netty In Action之传输(三)

    当我们的应用程序需要接受比预期多很多的并发连接的时候,我们需要从阻塞传输切换到非阻塞传输上去,如果是我们的网络编程是基于jdk提供的API进行开发地的话,这种传输模式的切换几乎要我们重构整个网络传输相 ...

  2. 一起来读Netty In Action之netty的组件和设计(二)

    在上一篇博客中,我们给出了java高性能网络编程的技术基础,也简单的介绍了netty的核心构件,在这一篇博客中,我们将更加详细的研究netty的各个组件,并且密切关注它们是如何通过协作来支撑这些体系结 ...

  3. Netty In Action中文版 - 第五章:Buffers(缓冲)

    本章介绍 ByteBuf ByteBufHolder ByteBufAllocator 使用这些接口分配缓冲和运行操作 每当你须要数据传输时,它必须包括一个缓冲区.Java NIO API自带的缓冲区 ...

  4. 《Netty in action》 读书笔记

    声明:这篇文章是记录读书过程中的知识点,并加以归纳总结,成文.文中图片.代码出自<Netty in action>. 1. 为什么用Netty? 每个框架的流行,都一定有它出众的地方.Ne ...

  5. Netty In Action中文版 - 第七章:编解码器Codec

    http://blog.csdn.net/abc_key/article/details/38041143 本章介绍 Codec,编解码器 Decoder,解码器 Encoder,编码器 Netty提 ...

  6. Netty | 第1章 Java NIO 网络编程《Netty In Action》

    目录 前言 1. Java 网络编程 1.1 Javs NIO 基本介绍 1.2 缓冲区 Buffer 1.2 通道 Channel 1.3 选择器 Selector 1.4 NIO 非阻塞网络编程原 ...

  7. 【推荐】《Netty in action》书籍

    最近准备开始阅读一下<Netty in action>并且准备构架设计一个分布式系统.用于新项目. 貌似压力很大啊.压力就是东西.希望自己能够调节好. Netty in action是Ne ...

  8. Netty In Action中国版 - 第二章:第一Netty程序

    本章介绍 获得Netty4最新的版本号 设置执行环境,以构建和执行netty程序 创建一个基于Netty的server和client 拦截和处理异常 编制和执行Nettyserver和client 本 ...

  9. Netty In Action中文版 - 第一章:Netty介绍

    本章介绍 Netty介绍 为什么要使用non-blocking IO(NIO) 堵塞IO(blocking IO)和非堵塞IO(non-blocking IO)对照 Java NIO的问题和在Nett ...

随机推荐

  1. android 开发从入门到精通

    Android-Tips This is an awesome list of tips for android. If you are a beginner, this list will be t ...

  2. EBS R12安装升级(FRESH)(四)

    7 升级Oracle数据库到11gR2 7.1 先打补丁7303030_zhs,9062910,8919489,8919489_ZHS ,9868229,10163753,11071569,97380 ...

  3. linux信号量与完成量

    信号量:    是用于保护临界区的一种常用方法,它的使用和自旋锁类似.与自旋锁相同,只有得到信号量的进程才能执行 临界区的代码.但是与自旋锁不同的是,当获取不到信号量时,进程不会原地打转而是进入休眠等 ...

  4. 【11】-java递归和非递归二叉树前序中序后序遍历

    二叉树的遍历 对于二叉树来讲最主要.最基本的运算是遍历. 遍历二叉树 是指以一定的次序访问二叉树中的每个结点.所谓 访问结点 是指对结点进行各种操作的简称.例如,查询结点数据域的内容,或输出它的值,或 ...

  5. c程序的编译

    linux系统下采用gcc进行编译,而在aix系统下采用xlc 进行编译. 附上aix安装xlc地址:https://www.ibm.com/developerworks/cn/aix/library ...

  6. java 深入理解内部类以及之间的调用关系

    什么是内部类 内部类是指在一个外部类的内部再定义一个类.内部类作为外部类的一个成员,并且依附于外部类而存在的.内部类可为静态,可用protected和private修饰(而外部类只能使用public和 ...

  7. OO开发思想:面向对象的开发方法(Object oriented,OO)

    面向对象的开发方法(Object oriented,OO)认为是好文章吧,拿来分享一下(转载) 面向对象的开发方法(Object oriented,OO) 从事软件开发的工程 师们常常有这样 的体会: ...

  8. 一个简单的例子搞懂ES6之Promise

    ES5中实现异步的常见方式不外乎以下几种: 1. 回调函数 2. 事件驱动 2. 自定义事件(根本上原理同事件驱动相同) 而ES6中的Promise的出现就使得异步变得非常简单.promise中的异步 ...

  9. Linux 下常用的Shell 命令

    英文原文链接:https://www.lopezferrando.com/30-interesting-shell-commands/ 1. 监控命令(每2秒运行一次) watch "ls ...

  10. kindeditor修改允许上传的图片、视频、音频大小

    在jsp文件夹下,有个upload_json.jsp文件,打开找到: //最大文件大小 ; 修改数值即可.默认1000000,即为1M.