diff --git a/docs/Netty/IOTechnologyBase/把被说烂的BIO、NIO、AIO再从头到尾扯一遍.md b/docs/Netty/IOTechnologyBase/把被说烂的BIO、NIO、AIO再从头到尾扯一遍.md index b4fabb1..1ff0a00 100644 --- a/docs/Netty/IOTechnologyBase/把被说烂的BIO、NIO、AIO再从头到尾扯一遍.md +++ b/docs/Netty/IOTechnologyBase/把被说烂的BIO、NIO、AIO再从头到尾扯一遍.md @@ -4,9 +4,9 @@ #### 1、流的概念和作用 -**流**:代表任何有能力产出数据的数据源对象或者是有能力接受数据的接收端对象。 -**流的本质**:数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。 -**流的作用**:为数据源和目的地建立一个输送通道。 +**流**:代表任何有能力产出数据的数据源对象或者是有能力接受数据的接收端对象。<Thinking in Java> +**流的本质**:数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。 +**流的作用**:为数据源和目的地建立一个输送通道。 Java 中将输入输出抽象称为流,就好像水管,将两个容器连接起来。流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流。 每个流只能是输入流或输出流的一种,不能同时具备两个功能,输入流只能进行读操作,对输出流只能进行写操作。在一个数据传输通道中,如果既要写入数据,又要读取数据,则要分别提供两个流。 @@ -37,7 +37,7 @@ BIO 中的阻塞,就是阻塞在 2 个地方: ![avatar](../../../images/Netty/非阻塞IO模型.png) -每次应用进程询问内核是否有数据报准备好,当有数据报准备好时,就进行拷贝数据报的操作,从内核拷贝到用户空间,和拷贝完成返回的这段时间,应用进程是阻塞的。但在没有数据报准备好时,并不会阻塞程序,内核直接返回未准备就绪的信号,等待应用进程的下一个轮寻。但是,轮寻对于 CPU 来说是较大的浪费,一般只有在特定的场景下才使用。 +每次应用进程询问内核是否有数据报准备好,当有数据报准备好时,就进行拷贝数据报的操作,从内核拷贝到用户空间,和拷贝完成返回的这段时间,应用进程是阻塞的。但在没有数据报准备好时,并不会阻塞程序,内核直接返回未准备就绪的信号,等待应用进程的下一个轮询。但是,轮询对于 CPU 来说是较大的浪费,一般只有在特定的场景下才使用。 Java 的 NIO 就是采用这种方式,当我们 new 了一个 socket 后我们可以设置它是非阻塞的。比如: @@ -52,7 +52,7 @@ serverSocketChannel.configureBlocking(false); 上面的代码是设置 ServerSocketChannel 为非阻塞,SocketChannel 也可以设置。 -从图中可以看到,当设置为非阻塞后,我们的 socket.read()方法就会立即得到一个返回结果(成功 or 失败),我们可以根据返回结果执行不同的逻辑,比如在失败时,我们可以做一些其他的事情。但事实上这种方式也是低效的,因为我们不得不使用轮询方法区一直问 OS:“我的数据好了没啊”。 +从图中可以看到,当设置为非阻塞后,我们的 socket.read()方法就会立即得到一个返回结果(成功 or 失败),我们可以根据返回结果执行不同的逻辑,比如在失败时,我们可以做一些其他的事情。但事实上这种方式也是低效的,因为我们不得不使用轮询方法去一直问 OS:“我的数据好了没啊”。 **NIO 不会在 recvfrom(询问数据是否准备好)时阻塞,但还是会在将数据从内核空间拷贝到用户空间时阻塞。一定要注意这个地方,Non-Blocking 还是会阻塞的。** @@ -60,7 +60,7 @@ serverSocketChannel.configureBlocking(false); ![avatar](../../../images/Netty/IO复用模型.png) -传统情况下 client 与 server 通信需要 3 个 socket(客户端的 socket,服务端的 serversocket,服务端中用来和客户端通信的 socket),而在 IO 多路复用中,客户端与服务端通信需要的不是 socket,而是 3 个 channel,通过 channel 可以完成与 socket 同样的操作,channel 的底层还是使用的 socket 进行通信,但是多个 channel 只对应一个 socket(可能不只是一个,但是 socket 的数量一定少于 channel 数量),这样仅仅通过少量的 socket 就可以完成更多的连接,提高了 client 容量。 +传统情况下 client 与 server 通信需要 3 个 socket(客户端的 socket,服务端的 server socket,服务端中用来和客户端通信的 socket),而在 IO 多路复用中,客户端与服务端通信需要的不是 socket,而是 3 个 channel,通过 channel 可以完成与 socket 同样的操作,channel 的底层还是使用的 socket 进行通信,但是多个 channel 只对应一个 socket(可能不只是一个,但是 socket 的数量一定少于 channel 数量),这样仅仅通过少量的 socket 就可以完成更多的连接,提高了 client 容量。 其中,不同的操作系统,对此有不同的实现: @@ -447,6 +447,6 @@ JDK1.7 升级了 NIO 类库,升级后的 NIO 类库被称为 NIO 2.0。Java 异步通道获取获取操作结果方式: 1. 使用 java.util.concurrent.Future 类表示异步操作的结果; -2. 在执行异步操作的时候传入一个 java.nio.channels,操作完成后胡回调 CompletionHandler 接口的实现类。 +2. 在执行异步操作的时候传入一个 java.nio.channels,操作完成后会回调 CompletionHandler 接口的实现类。 NIO 2.0 的异步套接字通道是真正的异步非阻塞 I/O,对应于 UNIX 网络编程中的事件驱动 I/O(AIO)。