1 introduction

1.2 Asynchronous by design

two most common ways to work with or implement an asynchronous API,

1.2.1 Callbacks

回调函数,本质,

move the execution of these methods from the “caller” thread to some other thread.
There is no guarantee whenever one of the methods of the FetchCallback will be called.

Callbacks的问题,影响可读性

lead to spaghetti code when you chain many asynchronous method calls with different callbacks

 

1.2.2 Futures

A Future is an abstraction, which represents a value that may become available at some point.
A Future object either holds the result of a computation or, in the case of a failed computation, an exception.

例子,

ExecutorService executor = Executors.newCachedThreadPool();

Runnable task1 = new Runnable() { }

Future<?> future1 = executor.submit(task1);
Future<Integer> future2 = executor.submit(task2);
while (!future1.isDone() || !future2.isDone()) {
...
// do something else
...
}

Future的问题在于,需要不时的去看看结果ready没有,比较ugly

Sometimes using futures can feel ugly because you need to check the state of the Future in intervals to see if it is completed yet, whereas with a callback you’re notified directly after it’s done.

 

1.3 Blocking versus non-blocking IO on the JVM

 

To do networking-related tasks in Java, you can take one of two approaches:

-  use IO , also known as blocking IO

-  use NIO, also known as new/non-blocking IO

 

1.3.1 EchoServer based on blocking IO

public class PlainEchoServer {
public void serve(int port) throws IOException {
final ServerSocket socket = new ServerSocket(port); #1
while (true) {
final Socket clientSocket = socket.accept(); #2 new Thread(new Runnable() { #3
@Override
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true);
while(true) { #4
writer.println(reader.readLine());
writer.flush();
}
}
} }

问题就是一个连接就需要一个thread,当连接很多的时候,有扩展性问题,就算用连接池,也是一样比较低效

 

1.3.2 Non-blocking IO basics

 

ByteBuffer

A ByteBuffer is fundamental to both NIO APIs and, indeed, to Netty. A ByteBuffer can either be allocated on the heap or directly

用于数据搬运的集装箱

flip操作用于reset offset,便于读取现有数据

 

WORKING With NIO Selectors

A selector is a NIO component that determines if one or more channels are ready for reading and/or writing, thus a single select selector can be used to handle multiple connections

类似于操作系统,select,poll的命令

To use selectors, you typically complete the following steps.

1. Create one or more selectors to which opened channels (sockets) can be registered.

2. When a channel is registered, you specify which events you’re interested in listening in.

The four available events (or Ops/operations) are:

- OP_ACCEPT—Operation-set bit for socket-accept operations

- OP_CONNECT—Operation-set bit for socket-connect operations

- OP_READ—Operation-set bit for read operations

- OP_WRITE—Operation-set bit for write operations

3. When channels are registered, you call the Selector.select() method to block until one of these events occurs.

4. When the method unblocks, you can obtain all of the SelectionKey instances (which hold the reference to the registered channel and to selected Ops) and do something.

What exactly you do depends on which operation is ready. A SelectedKey can include more than one operation at any given time.

创建selectors 让channels (sockets)可以注册上

然后,selector就会监听事件,事件有4种

调用Selector.select()会block等待事件,关键在于可以同时监听很多channel,所以是non-blocking

收到事件后,可以取到SelectionKey

 

1.3.3 EchoServer based on NIO

注册过程

ServerSocketChannel serverChannel = ServerSocketChannel.open(); //创建channel
ServerSocket ss = serverChannel.socket(); //channel创建和绑定socket
InetSocketAddress address = new InetSocketAddress(port);
ss.bind(address);
serverChannel.configureBlocking(false);
Selector selector = Selector.open(); //创建selector
serverChannel.register(selector, SelectionKey.OP_ACCEPT); //将channel注册到selector,监听Accept事件

处理过程,

while (true) {
try {
selector.select(); //Block until something is selected
} catch (IOException ex) {
ex.printStackTrace();
// handle in a proper way
break;
} Set readyKeys = selector.selectedKeys(); //Get all SelectedKey instances
Iterator iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove(); //Remove the SelectedKey from the iterator
try {
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.accept(); //Accept the client connection
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, ByteBuffer.allocate(100)); //accept后,需要继续注册读写OP
}
if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer output = (ByteBuffer) key.attachment();
client.read(output);
}
if (key.isWritable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer output = (ByteBuffer) key.attachment();
output.flip();
client.write(output);
output.compact();
}
}
}

可以看到典型的reactor模型,事件驱动

所有链接,都需要先处理accept请求,然后再注册读写OP

NIO是non-blocking,reactor模型是典型的非阻塞同步模型

 

1.3.4 EchoServer based on NIO.2

NIO2,是非阻塞异步模型

只需要调用IO操作,并给出CompletionHandler即可,这个CompletionHandler在IO操作完成后会异步的执行

并且还可以保证对于一个channel,只有一个CompletionHandler被执行

Unlike the original NIO implementation, NIO.2 allows you to issue IO operations and provide what is called a completion handler (CompletionHandler class).

It also guarantees that only one CompletionHandler is executed for channel at the same time.

This approach helps to simplify the code because it removes the complexity that comes with multithreaded execution.

public class PlainNio2EchoServer {
public void serve(int port) throws IOException {
final AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open(); //注意这里是异步ServerSocketChannel
InetSocketAddress address = new InetSocketAddress(port);
serverChannel.bind(address); serverChannel.accept(null, //触发accept操作,以CompletionHandler为callback
new CompletionHandler<AsynchronousSocketChannel, Object>() {
@Override
public void completed(final AsynchronousSocketChannel channel, Object attachment) { //当accept完成时异步调用
serverChannel.accept(null, this); //再次触发accept操作,接受其他的connection
ByteBuffer buffer = ByteBuffer.allocate(100);
channel.read(buffer, buffer, new EchoCompletionHandler(channel)); //触发读操作,并以EchoCompletionHandler为callback
}
@Override
public void failed(Throwable throwable, Object attachment) {
try {
serverChannel.close(); //IO失败时候的处理
} catch (IOException e) {
// ingnore on close
}
}
}
} private final class EchoCompletionHandler implements CompletionHandler<Integer, ByteBuffer> {
private final AsynchronousSocketChannel channel; @Override
public void completed(Integer result, ByteBuffer buffer) { //当读操作完成时调用
buffer.flip();
channel.write(buffer, buffer, //触发写操作
new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer buffer) { //写操作完成后的callback
if (buffer.hasRemaining()) {
channel.write(buffer, buffer, this); //如果buffer里面还有数据,继续写
} else {
buffer.compact();
channel.read(buffer, buffer, EchoCompletionHandler.this); //如果没有,继续触发读操作,并以EchoCompletionHandler为callback
}
} @Override
public void failed(Throwable exc, ByteBuffer attachment) {
try {
channel.close();
} catch (IOException e) {
// ingnore on close
}
}

大家体会一下,这个代码比NIO更加tricky和难于理解

 

1.4 NIO problems and how Netty comes to the rescue

看看NIO的问题,以及Netty是如何解决的

1.4.1 Cross-platform and compatibility issues

NIO is low level and depends on how the operating system (OS) handles IO.

When using NIO you often find that your code works fine on Linux, for example, but has problems on Windows.

Ideal as NIO.2 may seem, it’s only supported in Java 7, and if your application runs on Java 6, you may not be able to use it. Also, at the time of writing, there is no NIO.2 API for datagram channels (for UDP applications), so its usage is limited to TCP applications only.

Java NIO和系统和Java版本相关

 

1.4.2 Extending ByteBuffer ... or not

As you saw previously, ByteBuffer is used as data container. Unfortunately, the JDK doesn’t contain a ByteBuffer implementation that allows wrapping an array of ByteBuffer instances. This functionality is useful if you want to minimize memory copies. If you ‘rethinking I’ll implement it myself, don’t waste your time; ByteBuffer has a private constructor, so it isn’t possible to extend it.

ByteBuffer具有私有的构造函数,无法扩展

不一一列了,后面大部分是一些系统或java的bug,netty修复了。。。。。。感觉理由不太充分啊

 

Bootstrapping

Bootstrapping in Netty is the process by which you configure your Netty application.

You use a bootstrap when you need to connect a client to some host and port, or bind a server to a given port.

As the previous statement implies, there are two types of Bootstraps, one typically used for clients, but is also used for DatagramChannel (simply called Bootstrap) and one for servers (aptly named ServerBootstrap).

提供Bootstrap抽象,用于配置和初始化

只有两种类型,对应于client和server,两种Bootstrap的不同

第一个不同很容易理解

第二个不同,看着很无厘头,但很关键,关键就在ServerBootstrap为什么要两个?

看下图,

EventLoopGroup A's only purpose is to accept connections and hand them over to EventLoopGroup B.

用两个reactor模型来模拟proactor模型,

第一个reactor只accept,这样避免在handler的时间过长,而产生block

第二个reactor去真正处理handler

所以Netty Server可以说是非阻塞异步IO

 

Bootstrap client

 

The bootstrap is responsible for client and/or connectionless-based channels, so it will create the channel after bind(...) or connect(...) is called.

 

 

Server Bootstrap

As you may have noticed, the methods in the previous section are similar to what you saw in the bootstrap class.

There is only one difference, which makes a lot of sense once you think about it.

While ServerBootstrap has handler(...), attr(...), and option(...) methods, it also offers those with the child prefix.

This is done as the ServerBootstrap bootstraps ServerChannel implementations, which are responsible for creating child channels.

Those channels represent the accepted connections. ServerBootstrap offer the child* methods in order to make applying settings on accepted channels as easy as possible.

 

 

Adding multiple ChannelHandlers during a bootstrap

 

ChannelPipeline

A ChannelPipeline is a list of ChannelHandler instances that handle or intercept inbound and outbound operations of a channel.

ChannelHandler的操作,

其他操作,

Inbound operations

 

Outbound operations

 

ChannelHandlerContext

 

Now if you’d like to have the event flow through the whole ChannelPipeline, there are two different ways of doing so:

- Invoke methods on the Channel.

- Invoke methods on the ChannelPipeline.

 

 

 

除了上面两种方式,还可以调用ChannelContext的接口,

这样的不同是,可以从任意一个handler开始执行,而不需要从头执行

 

ChannelHandlers and their types

 

 

 

 

这书仅第一章写的不错,思路清晰

后面的比较一般,思路不是很好

Netty In Action的更多相关文章

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

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

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

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

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

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

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

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

  5. [Netty] - Netty IN ACTION(导言)

    最近没什么事儿做,刚好看到有需要网络编程的知识,java中有NIO和IO两种不同的方式,但是NIO的编写比较麻烦,刚好找到一个成熟的网络框架Netty.接下来的一个月就准备将Netty IN ACTI ...

  6. 《Netty in action》 读书笔记

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

  7. Netty in action—Netty中的ByteBuf

    Netty in action—Netty中的ByteBuf - 日积月累 - CSDN博客 https://blog.csdn.net/yjw123456/article/details/77843 ...

  8. 《Netty in action》目录修复版本分享

    最近阅读了Netty in action一书.深感外国友人的书籍编写能力强大.作者由简入深.精简描述了Netty的相关知识,如何使用等等. 本来想翻译一下的.尝试着翻译了一点之后.发现非常痛苦啊.ps ...

  9. Netty In Action中文版 - 第四章:Transports(传输)

    本章内容 Transports(传输) NIO(non-blocking IO,New IO), OIO(Old IO,blocking IO), Local(本地), Embedded(嵌入式) U ...

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

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

随机推荐

  1. androi手机解锁引导程序

    1.重启手机进入fastboot模式  一般关机状态下按手机音量减+开机键,成功后会显示fastboot字提示. 2.查看设备信息 fastboot devices 说明:fastboot是一个工具软 ...

  2. ecshop商品子分类点击下拉,子分类空时,直接跳转功能

    模板文件循环读取商品分类,并给大分类加上url属性.然后在js中判断是否有下级分类.有分类则点击下拉效果,没有子分类则跳转到url属性的链接去. themes/**/library/category_ ...

  3. jQuery UI Datepicker

    http://www.runoob.com/try/try.php?filename=jqueryui-example-datepicker-dropdown-month-year <!doct ...

  4. VIM插件攻略

    工欲善其事,必先利其器.一个强大的开发环境可以大大提高工作效率.好吧,我知道这是废话...不过,我想一定有很多跟我一样打算进入Linux平台开发的新手,一开始都为找不到一个像Windows下的VS那样 ...

  5. VC++ 一个简单的Log类

    在软件开发中,为程序建立Log日志是很必要的,它可以记录程序运行的状态以及出错信息,方便维护和调试. 下面实现了一个简单的Log类,使用非常简单,仅供参考. // CLogHelper.h : hea ...

  6. PHP-----练习-------租房子-----增删改查,多条件查询

    练习-------租房子-----增删改查,多条件 一 .题目要求: 二 .做法: [1]建立数据库 [2]封装类文件------DBDA.class.php <?php class DBDA ...

  7. QQ付费群规则重大变更!特别是这类群!

    很多人都是知道现在QQ有个付费群功能.以往加群需要你填写一些验证信息给管理员,管理员看你顺眼就放你进去,不顺眼你就进不去了.另外还有一些打广告的人难免会被管理员误判给放进去,令管理员苦恼不已,总有审核 ...

  8. Android笔记:HTTP相关

    发送HTTP请求 HttpURLConnection.HttpClient XML解析 Pull 解析.SAX 解析.DOM 解析 解析JSON 格式数据 官方提供的JSONObject.谷歌的开源库 ...

  9. CSS初始化样式

    为什么要初始化CSS? CSS初始化是指重设浏览器的样式.不同的浏览器默认的样式可能不尽相同,所以开发时的第一件事可能就是如何把它们统一.如果没对CSS初始化往往会出现浏览器之间的页面差异.每次新开发 ...

  10. 【转】如何使用VS 2013发布一个可以在Windows XP中独立运行的可执行文件

    问题描述: 用VS2013写好一个程序,在本机上运行一切正常.但是如果直接把exe文件放到另一台机器上用,则会出现: Windows XP:不是一个正常的win32程序 Window 7:缺少msvc ...