auto commit
This commit is contained in:
301
notes/Java IO.md
301
notes/Java IO.md
@ -1,129 +1,130 @@
|
||||
<!-- GFM-TOC -->
|
||||
* [<EFBFBD><EFBFBD><EFBFBD><EFBFBD>](#<EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||
* [<EFBFBD><EFBFBD><EFBFBD>̲<EFBFBD><EFBFBD><EFBFBD>](#<23><><EFBFBD>̲<EFBFBD><CCB2><EFBFBD>)
|
||||
* [<EFBFBD>ֽڲ<EFBFBD><EFBFBD><EFBFBD>](#<23>ֽڲ<D6BD><DAB2><EFBFBD>)
|
||||
* [<EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](#<23>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD>)
|
||||
* [<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](#<23><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||
* [<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](#<23><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||
* [概览](#概览)
|
||||
* [磁盘操作](#磁盘操作)
|
||||
* [字节操作](#字节操作)
|
||||
* [字符操作](#字符操作)
|
||||
* [对象操作](#对象操作)
|
||||
* [网络操作](#网络操作)
|
||||
* [1. InetAddress](#1-inetaddress)
|
||||
* [2. URL](#2-url)
|
||||
* [3. Sockets](#3-sockets)
|
||||
* [4. Datagram](#4-datagram)
|
||||
* [NIO](#nio)
|
||||
* [1. <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](#1-<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||
* [2. ͨ<EFBFBD><EFBFBD><EFBFBD>뻺<EFBFBD><EFBFBD><EFBFBD><EFBFBD>](#2-ͨ<><CDA8><EFBFBD>뻺<EFBFBD><EBBBBA><EFBFBD><EFBFBD>)
|
||||
* [2.1 ͨ<EFBFBD><EFBFBD>](#21-ͨ<EFBFBD><EFBFBD>)
|
||||
* [2.2 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](#22-<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||
* [3. <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD>](#3-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬<D7B4><CCAC><EFBFBD><EFBFBD>)
|
||||
* [4. <EFBFBD><EFBFBD>д<EFBFBD>ļ<EFBFBD>ʵ<EFBFBD><EFBFBD>](#4-<2D><>д<EFBFBD>ļ<EFBFBD>ʵ<EFBFBD><CAB5>)
|
||||
* [5. <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](#5-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||
* [5.1 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ I/O](#51-<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ-io)
|
||||
* [5.2 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ I/O](#52-<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ-io)
|
||||
* [6. <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD>](#6-<2D><EFBFBD><D7BD><EFBFBD>ʵ<EFBFBD><CAB5>)
|
||||
* [1. 流与块](#1-流与块)
|
||||
* [2. 通道与缓冲区](#2-通道与缓冲区)
|
||||
* [2.1 通道](#21-通道)
|
||||
* [2.2 缓冲区](#22-缓冲区)
|
||||
* [3. 缓冲区状态变量](#3-缓冲区状态变量)
|
||||
* [4. 读写文件实例](#4-读写文件实例)
|
||||
* [5. 阻塞与非阻塞](#5-阻塞与非阻塞)
|
||||
* [5.1 阻塞式 I/O](#51-阻塞式-io)
|
||||
* [5.2 非阻塞式 I/O](#52-非阻塞式-io)
|
||||
* [6. 套接字实例](#6-套接字实例)
|
||||
* [6.1 ServerSocketChannel](#61-serversocketchannel)
|
||||
* [6.2 Selectors](#62-selectors)
|
||||
* [6.3 <EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD>](#63-<EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD>)
|
||||
* [6.4 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](#64-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||
* [6.5 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](#65-<2D><><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD><EFBFBD>)
|
||||
* [6.6 ɾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SelectionKey](#66-ɾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-selectionkey)
|
||||
* [6.7 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> I/O](#67-<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-io)
|
||||
* [<EFBFBD>ο<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](#<23>ο<EFBFBD><CEBF><EFBFBD><EFBFBD><EFBFBD>)
|
||||
* [6.3 主循环](#63-主循环)
|
||||
* [6.4 监听新连接](#64-监听新连接)
|
||||
* [6.5 接受新的连接](#65-接受新的连接)
|
||||
* [6.6 删除处理过的 SelectionKey](#66-删除处理过的-selectionkey)
|
||||
* [6.7 传入的 I/O](#67-传入的-io)
|
||||
* [参考资料](#参考资料)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
# <20><><EFBFBD><EFBFBD>
|
||||
|
||||
Java <20><> I/O <20><><EFBFBD>ſ<EFBFBD><C5BF>Էֳ<D4B7><D6B3><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>
|
||||
# 概览
|
||||
|
||||
1. <20><><EFBFBD>̲<EFBFBD><CCB2><EFBFBD><EFBFBD><EFBFBD>File
|
||||
2. <20>ֽڲ<D6BD><DAB2><EFBFBD><EFBFBD><EFBFBD>InputStream <20><> OutputStream
|
||||
3. <20>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Reader <20><> Writer
|
||||
4. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Serializable
|
||||
5. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Socket
|
||||
6. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ IO<49><4F>NIO
|
||||
Java 的 I/O 大概可以分成以下几类
|
||||
|
||||
# <20><><EFBFBD>̲<EFBFBD><CCB2><EFBFBD>
|
||||
1. 磁盘操作:File
|
||||
2. 字节操作:InputStream 和 OutputStream
|
||||
3. 字符操作:Reader 和 Writer
|
||||
4. 对象操作:Serializable
|
||||
5. 网络操作:Socket
|
||||
6. 非阻塞式 IO:NIO
|
||||
|
||||
File <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڱ<EFBFBD>ʾ<EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>Ŀ¼<C4BF><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD><D6BB><EFBFBD>ڱ<EFBFBD>ʾ<EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD><CFA2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݡ<EFBFBD>
|
||||
# 磁盘操作
|
||||
|
||||
# <20>ֽڲ<D6BD><DAB2><EFBFBD>
|
||||
File 类可以用于表示文件和目录,但是它只用于表示文件的信息,而不表示文件的内容。
|
||||
|
||||

|
||||
# 字节操作
|
||||
|
||||
Java I/O ʹ<><CAB9><EFBFBD><EFBFBD>װ<EFBFBD><D7B0><EFBFBD><EFBFBD>ģʽ<C4A3><CABD>ʵ<EFBFBD>֡<EFBFBD><D6A1><EFBFBD> InputStream Ϊ<><CEAA><EFBFBD><EFBFBD>InputStream <20>dz<EFBFBD><C7B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>FileInputStream <20><> InputStream <20><><EFBFBD><EFBFBD><EFBFBD>࣬<EFBFBD><E0A3AC><EFBFBD>ھ<EFBFBD><DABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ṩ<EFBFBD><E1B9A9><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>FilterInputStream <20><><EFBFBD>ڳ<EFBFBD><DAB3><EFBFBD>װ<EFBFBD><D7B0><EFBFBD>ߣ<EFBFBD>װ<EFBFBD><D7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װ<EFBFBD><D7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD>ṩ<EFBFBD><E1B9A9><EFBFBD><EFBFBD><EFBFBD>Ĺ<EFBFBD><C4B9>ܣ<EFBFBD><DCA3><EFBFBD><EFBFBD><EFBFBD> BufferedInputStream Ϊ FileInputStream <20>ṩ<EFBFBD><E1B9A9><EFBFBD><EFBFBD><EFBFBD>Ĺ<EFBFBD><C4B9>ܡ<EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB>湦<EFBFBD>ܵ<EFBFBD><DCB5>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>ֻ<EFBFBD><D6BB>Ҫ<EFBFBD><D2AA> FileInputStream <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> BufferedInputStream <20><><EFBFBD>ɡ<F3BCB4BF>
|
||||

|
||||
|
||||
Java I/O 使用了装饰者模式来实现。以 InputStream 为例,InputStream 是抽象组件,FileInputStream 是 InputStream 的子类,属于具体组件,提供了字节流的输入操作。FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件提供额外的功能,例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。
|
||||
|
||||
```java
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
||||
```
|
||||
|
||||
DataInputStream װ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ṩ<EFBFBD>˶Ը<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> int<EFBFBD><EFBFBD>double <EFBFBD>Ȼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͡<EFBFBD>
|
||||
DataInputStream 装饰者提供了对更多数据类型进行输入的操作,比如 int、double 等基本类型。
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD><EFBFBD>ֽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
批量读入文件中的内容到字节数组中
|
||||
|
||||
```java
|
||||
byte[] buf = new byte[20*1024];
|
||||
int bytes = 0;
|
||||
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ buf.length <EFBFBD><EFBFBD><EFBFBD>ֽڣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>ʶ<EFBFBD>ȡ<EFBFBD>ĸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> -1 <20><>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD> eof<6F><66><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>β
|
||||
// 最多读取 buf.length 个字节,返回的是实际读取的个数,返回 -1 的时候表示读到 eof,即文件尾
|
||||
while((bytes = in.read(buf, 0 , buf.length)) != -1) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
# <EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
# 字符操作
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǵ<EFBFBD><EFBFBD>̻<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>紫<EFBFBD>䣬<EFBFBD><EFBFBD>С<EFBFBD>Ĵ洢<EFBFBD><EFBFBD>Ԫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽڣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> I/O <20><><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD><EFBFBD>ֽڶ<D6BD><DAB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڳ<EFBFBD><DAB3><EFBFBD><EFBFBD>в<EFBFBD><D0B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>ṩ<EFBFBD><E1B9A9><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD>в<EFBFBD><D0B2><EFBFBD><EFBFBD>ķ<EFBFBD><C4B7><EFBFBD><EFBFBD><EFBFBD>
|
||||
不管是磁盘还是网络传输,最小的存储单元都是字节,而不是字符,所以 I/O 操作的都是字节而不是字符。但是在程序中操作的数据通常是字符形式,因此需要提供对字符进行操作的方法。
|
||||
|
||||
InputStreamReader ʵ<EFBFBD>ִ<EFBFBD><EFBFBD>ı<EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>OutputStreamWriter ʵ<><CAB5><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>ı<EFBFBD><C4B1>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƕ<EFBFBD><C7B6>̳<EFBFBD><CCB3><EFBFBD> Reader <EFBFBD><EFBFBD> Writer<EFBFBD><EFBFBD>
|
||||
InputStreamReader 实现从文本文件的字节流解码成字符流;OutputStreamWriter 实现字符流编码成为文本文件的字节流。它们都继承自 Reader 和 Writer。
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD>ַ<EFBFBD>ת<EFBFBD><EFBFBD>Ϊ<EFBFBD>ֽڣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD>ֽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϳ<EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>
|
||||
编码就是把字符转换为字节,而解码是把字节重新组合成字符。
|
||||
|
||||
```java
|
||||
byte[] bytes = str.getBytes(encoding); // <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
String str = new String(bytes, encoding)<EFBFBD><EFBFBD> // <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
byte[] bytes = str.getBytes(encoding); // 编码
|
||||
String str = new String(bytes, encoding); // 解码
|
||||
```
|
||||
|
||||
GBK <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ռ 2 <20><><EFBFBD>ֽڣ<D6BD>Ӣ<EFBFBD><D3A2>ռ 1 <20><><EFBFBD>ֽڣ<D6BD>UTF-8 <20><><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD><EFBFBD>ռ 3 <20><><EFBFBD>ֽڣ<D6BD>Ӣ<EFBFBD><D3A2>ռ 1 <20><><EFBFBD>ֽڣ<D6BD>Java ʹ<><CAB9>˫<EFBFBD>ֽڱ<D6BD><DAB1><EFBFBD> UTF-16be<62><65><EFBFBD><EFBFBD><EFBFBD>ĺ<EFBFBD>Ӣ<EFBFBD>Ķ<EFBFBD>ռ 2 <20><><EFBFBD>ֽڡ<D6BD>
|
||||
GBK 编码中,中文占 2 个字节,英文占 1 个字节;UTF-8 编码中,中文占 3 个字节,英文占 1 个字节;Java 使用双字节编码 UTF-16be,中文和英文都占 2 个字节。
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ò<EFBFBD>ͬ<EFBFBD>ı<EFBFBD><EFBFBD>뷽ʽ<EFBFBD><EFBFBD>ô<EFBFBD>ͳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>롣
|
||||
如果编码和解码过程使用不同的编码方式那么就出现了乱码。
|
||||
|
||||
# <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
# 对象操作
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǽ<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>洢<EFBFBD>ʹ<EFBFBD><EFBFBD>䡣
|
||||
序列化就是将一个对象转换成字节序列,方便存储和传输。
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><EFBFBD><EFBFBD>ObjectOutputStream.writeObject()
|
||||
序列化:ObjectOutputStream.writeObject()
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><EFBFBD><EFBFBD>ObjectInputStream.readObject()
|
||||
反序列化:ObjectInputStream.readObject()
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫʵ<EFBFBD><EFBFBD> Serializable <20>ӿڣ<D3BF><DAA3><EFBFBD>ֻ<EFBFBD><D6BB>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><D7BC>û<EFBFBD><C3BB><EFBFBD>κη<CEBA><CEB7><EFBFBD><EFBFBD><EFBFBD>Ҫʵ<D2AA>֡<EFBFBD>
|
||||
序列化的类需要实现 Serializable 接口,它只是一个标准,没有任何方法需要实现。
|
||||
|
||||
transient <EFBFBD>ؼ<EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD><EFBFBD>ʹһЩ<EFBFBD><EFBFBD><EFBFBD>Բ<EFBFBD><EFBFBD>ᱻ<EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><EFBFBD><EFBFBD>
|
||||
transient 关键字可以使一些属性不会被序列化。
|
||||
|
||||
**ArrayList <EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><EFBFBD>ͷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD>**<EFBFBD><EFBFBD>ArrayList <EFBFBD>д洢<EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> transient <20><><EFBFBD>εģ<CEB5><C4A3><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƕ<EFBFBD>̬<EFBFBD><CCAC>չ<EFBFBD>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>еĿռ䶼<D5BC><E4B6BC>ʹ<EFBFBD>ã<EFBFBD><C3A3><EFBFBD><EFBFBD>˾Ͳ<CBBE><CDB2><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD>ݶ<EFBFBD><DDB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD>л<EFBFBD><D0BB>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD>ֻ<EFBFBD><D6BB><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD><DDB5>Dz<EFBFBD><C7B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݡ<EFBFBD>
|
||||
**ArrayList 序列化和反序列化的实现**:ArrayList 中存储数据的数组是用 transient 修饰的,因为这个数组是动态扩展的,并不是所有的空间都被使用,因此就不需要所有的内容都被序列化。通过重写序列化和反序列化方法,使得可以只序列化数组中有内容的那部分数据。
|
||||
|
||||
```
|
||||
private transient Object[] elementData;
|
||||
```
|
||||
|
||||
# <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
# 网络操作
|
||||
|
||||
Java <EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֧<EFBFBD>֣<EFBFBD>
|
||||
Java 中的网络支持:
|
||||
|
||||
1. InetAddress<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڱ<EFBFBD>ʾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> IP <20><>ַ<EFBFBD><D6B7>
|
||||
2. URL<EFBFBD><EFBFBD>ͳһ<EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD> URL <20><><EFBFBD><EFBFBD>ֱ<EFBFBD>Ӷ<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD><CFB5><EFBFBD><EFBFBD>ݣ<EFBFBD>
|
||||
3. Sockets<EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD> TCP Э<><D0AD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD>ţ<EFBFBD>
|
||||
4. Datagram<EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD> UDP Э<><D0AD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD>š<EFBFBD>
|
||||
1. InetAddress:用于表示网络上的硬件资源,即 IP 地址;
|
||||
2. URL:统一资源定位符,通过 URL 可以直接读取或者写入网络上的数据;
|
||||
3. Sockets:使用 TCP 协议实现网络通信;
|
||||
4. Datagram:使用 UDP 协议实现网络通信。
|
||||
|
||||
## 1. InetAddress
|
||||
|
||||
û<EFBFBD>й<EFBFBD><EFBFBD>й<EFBFBD><EFBFBD>캯<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> InetAddress.getByName(String host)<EFBFBD><EFBFBD>InetAddress.getByAddress(byte[] addr)<EFBFBD><EFBFBD>
|
||||
没有公有构造函数,只能通过静态方法来创建实例,比如 InetAddress.getByName(String host)、InetAddress.getByAddress(byte[] addr)。
|
||||
|
||||
## 2. URL
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD>Ӵ<EFBFBD> URL <20>ж<EFBFBD>ȡ<EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
可以直接从 URL 中读取字节流数据
|
||||
|
||||
```java
|
||||
URL url = new URL("http://www.baidu.com");
|
||||
InputStream is = url.openStream(); // <EFBFBD>ֽ<EFBFBD><EFBFBD><EFBFBD>
|
||||
InputStreamReader isr = new InputStreamReader(is, "utf-8"); // <EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>
|
||||
InputStream is = url.openStream(); // 字节流
|
||||
InputStreamReader isr = new InputStreamReader(is, "utf-8"); // 字符流
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
String line = br.readLine();
|
||||
while (line != null) {
|
||||
@ -137,56 +138,56 @@ is.close();
|
||||
|
||||
## 3. Sockets
|
||||
|
||||
Socket ͨ<EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD>
|
||||
Socket 通信模型
|
||||
|
||||

|
||||

|
||||
|
||||
- ServerSocket<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
- Socket<EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
- ServerSocket:服务器端类
|
||||
- Socket:客户端类
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϳͻ<EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD> InputStream <EFBFBD><EFBFBD> OutputStream <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
服务器和客户端通过 InputStream 和 OutputStream 进行输入输出。
|
||||
|
||||
## 4. Datagram
|
||||
|
||||
- DatagramPacket<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݰ<EFBFBD><EFBFBD><EFBFBD>
|
||||
- DatagramSocket<EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
- DatagramPacket:数据包类
|
||||
- DatagramSocket:通信类
|
||||
|
||||
# NIO
|
||||
|
||||
NIO <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD> I/O <20><><EFBFBD><EFBFBD> ( <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ) ת<>ƻز<C6BB><D8B2><EFBFBD>ϵͳ<CFB5><CDB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>Աȥ<D4B1><C8A5><EFBFBD>ƾͿ<C6BE><CDBF>Լ<EFBFBD><D4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٶȡ<D9B6>
|
||||
NIO 将最耗时的 I/O 操作 ( 即填充和提取缓冲区 ) 转移回操作系统,因而 不需要程序员去控制就可以极大地提高运行速度。
|
||||
|
||||
## 1. <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
## 1. 流与块
|
||||
|
||||
I/O <EFBFBD><EFBFBD> NIO <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD>ᵽ<EFBFBD>ģ<EFBFBD>I/O <20><><EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݣ<EFBFBD><DDA3><EFBFBD> NIO <20>Կ<EFBFBD><D4BF>ķ<EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݡ<EFBFBD>
|
||||
I/O 与 NIO 最重要的区别是数据打包和传输的方式。正如前面提到的,I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> I/O һ<><D2BB>һ<EFBFBD><D2BB><EFBFBD>ֽڽ<D6BD><DABD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݣ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ֽڵ<D6BD><DAB5><EFBFBD><EFBFBD>ݣ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ֽڵ<D6BD><DAB5><EFBFBD><EFBFBD>ݡ<EFBFBD>Ϊ<EFBFBD><CEAA>ʽ<EFBFBD><CABD><EFBFBD>ݴ<EFBFBD><DDB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>dz<EFBFBD><C7B3><EFBFBD><EFBFBD>ף<EFBFBD><D7A3><EFBFBD><EFBFBD>Ӽ<EFBFBD><D3BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ա<EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD><D6BB><EFBFBD><EFBFBD><F0B5A5B8><EFBFBD><EFBFBD>Ӵ<EFBFBD><D3B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD>֣<EFBFBD><D6A3><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD><EFBFBD>Լġ<F2B5A5B5><C4A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ǣ<EFBFBD><C7A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> I/O ͨ<><CDA8><EFBFBD>൱<EFBFBD><E0B5B1><EFBFBD><EFBFBD>
|
||||
面向流的 I/O 一次一个字节进行处理数据,一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。为流式数据创建过滤器非常容易,链接几个过滤器,以便每个过滤器只负责单个复杂处理机制的一部分,这样也是相对简单的。不利的一面是,面向流的 I/O 通常相当慢。
|
||||
|
||||
һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> I/O ϵͳ<CFB5>Կ<EFBFBD><D4BF><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݣ<EFBFBD>ÿһ<C3BF><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>в<EFBFBD><D0B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>ݿ顣<DDBF><E9A1A3><EFBFBD>鴦<EFBFBD><E9B4A6><EFBFBD><EFBFBD><EFBFBD>ݱȰ<DDB1><C8B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD>öࡣ<C3B6><E0A1A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> I/O ȱ<><C8B1>һЩ<D2BB><D0A9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> I/O <20><><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ժͼ<D4BA><CDBC><EFBFBD><EFBFBD>ԡ<EFBFBD>
|
||||
一个面向块的 I/O 系统以块的形式处理数据,每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按流处理数据要快得多。但是面向块的 I/O 缺少一些面向流的 I/O 所具有的优雅性和简单性。
|
||||
|
||||
I/O <EFBFBD><EFBFBD><EFBFBD><EFBFBD> NIO <EFBFBD>Ѿ<EFBFBD><EFBFBD>ܺõؼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˣ<EFBFBD>java.io.\* <20>Ѿ<EFBFBD><D1BE><EFBFBD> NIO Ϊ<><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD>ˣ<EFBFBD><CBA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> NIO <20><>һЩ<D2BB><D0A9><EFBFBD>ԡ<EFBFBD><D4A1><EFBFBD><EFBFBD>磬 java.io.\* <20><><EFBFBD>е<EFBFBD>һЩ<D2BB><D0A9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Կ<EFBFBD><D4BF><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD>д<EFBFBD><D0B4><EFBFBD>ݵķ<DDB5><C4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ü<EFBFBD>ʹ<EFBFBD>ڸ<EFBFBD><DAB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵͳ<CFB5>У<EFBFBD><D0A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٶ<EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD><EFBFBD>졣
|
||||
I/O 包和 NIO 已经很好地集成了,java.io.\* 已经以 NIO 为基础重新实现了,所以现在它可以利用 NIO 的一些特性。例如, java.io.\* 包中的一些类包含以块的形式读写数据的方法,这使得即使在更面向流的系统中,处理速度也会更快。
|
||||
|
||||
## 2. ͨ<EFBFBD><EFBFBD><EFBFBD>뻺<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
## 2. 通道与缓冲区
|
||||
|
||||
### 2.1 ͨ<EFBFBD><EFBFBD>
|
||||
### 2.1 通道
|
||||
|
||||
ͨ<EFBFBD><EFBFBD> Channel <EFBFBD>Ƕ<EFBFBD>ԭ I/O <EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD>⣬<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݡ<EFBFBD>
|
||||
通道 Channel 是对原 I/O 包中的流的模拟,可以通过它读取和写入数据。
|
||||
|
||||
ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD>֮ͬ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڣ<EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD><EFBFBD><EFBFBD>(һ<><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> InputStream <EFBFBD><EFBFBD><EFBFBD><EFBFBD> OutputStream <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<29><> <20><>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD>˫<EFBFBD><CBAB><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD><DAB6><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD>ͬʱ<CDAC><CAB1><EFBFBD>ڶ<EFBFBD>д<EFBFBD><D0B4>
|
||||
通道与流的不同之处在于,流只能在一个方向上移动,(一个流必须是 InputStream 或者 OutputStream 的子类), 而通道是双向的,可以用于读、写或者同时用于读写。
|
||||
|
||||
ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD>
|
||||
通道包括以下类型:
|
||||
|
||||
- FileChannel<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD>ж<EFBFBD>д<EFBFBD><EFBFBD><EFBFBD>ݣ<EFBFBD>
|
||||
- DatagramChannel<EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD> UDP <20><>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݣ<EFBFBD>
|
||||
- SocketChannel<EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD> TCP <20><>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݣ<EFBFBD>
|
||||
- ServerSocketChannel<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> TCP <20><><EFBFBD>ӣ<EFBFBD><D3A3><EFBFBD>ÿһ<C3BF><D2BB><EFBFBD>½<EFBFBD><C2BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӷ<EFBFBD><D3B6>ᴴ<EFBFBD><E1B4B4>һ<EFBFBD><D2BB> SocketChannel<EFBFBD><EFBFBD>
|
||||
- FileChannel:从文件中读写数据;
|
||||
- DatagramChannel:通过 UDP 读写网络中数据;
|
||||
- SocketChannel:通过 TCP 读写网络中数据;
|
||||
- ServerSocketChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。
|
||||
|
||||
### 2.2 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
### 2.2 缓冲区
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȷŵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD>ͬ<EFBFBD><EFBFBD><EFBFBD>أ<EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>κ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݶ<EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD>Ҳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>˵<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD>Ӷ<EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>д<EFBFBD><EFBFBD><EFBFBD>ݣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
发送给一个通道的所有对象都必须首先放到缓冲区中;同样地,从通道中读取的任何数据都要读到缓冲区中。也就是说,不会直接对通道进行读写数据,而是先经过缓冲区。
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>飬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>顣<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ṩ<EFBFBD>˶<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵĽṹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ը<EFBFBD><EFBFBD><EFBFBD>ϵͳ<EFBFBD>Ķ<EFBFBD>/д<><D0B4><EFBFBD>̡<EFBFBD>
|
||||
缓冲区实质上是一个数组,但它不仅仅是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD>
|
||||
缓冲区包括以下类型:
|
||||
|
||||
- ByteBuffer
|
||||
- CharBuffer
|
||||
@ -197,50 +198,50 @@ I/O
|
||||
- DoubleBuffer
|
||||
|
||||
|
||||
## 3. <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
## 3. 缓冲区状态变量
|
||||
|
||||
- capacity<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
- position<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD>Ѿ<EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
- limit<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD>д<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
- capacity:最大容量;
|
||||
- position:当前已经读写的字节数;
|
||||
- limit:还可以读写的字节数。
|
||||
|
||||
״̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĸı<EFBFBD><EFBFBD><EFBFBD><EFBFBD>̣<EFBFBD>
|
||||
状态变量的改变过程:
|
||||
|
||||
1\. <EFBFBD>½<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>СΪ 8 <20><><EFBFBD>ֽڵĻ<DAB5><C4BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ position Ϊ 0<EFBFBD><EFBFBD><EFBFBD><EFBFBD> limit == capacity == 9<EFBFBD><EFBFBD>capacity <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ı䣬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
1\. 新建一个大小为 8 个字节的缓冲区,此时 position 为 0,而 limit == capacity == 9。capacity 变量不会改变,下面的讨论会忽略它。
|
||||
|
||||

|
||||

|
||||
|
||||
2\. <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>ȡ 3 <20><><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD>뻺<EFBFBD><EBBBBA><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD>ʱ position <20>ƶ<EFBFBD><C6B6><EFBFBD>Ϊ 3<><33>limit <20><><EFBFBD>ֲ<EFBFBD><D6B2>䡣
|
||||
2\. 从输入通道中读取 3 个字节数据写入缓冲区中,此时 position 移动设为 3,limit 保持不变。
|
||||
|
||||

|
||||

|
||||
|
||||
3\. <EFBFBD>ڽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>֮ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>ȵ<EFBFBD><EFBFBD><EFBFBD> flip() <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> limit <20><><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>ǰ position<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> position <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ 0<><30>
|
||||
3\. 在将缓冲区的数据写到输出通道之前,需要先调用 flip() 方法,这个方法将 limit 设置为当前 position,并将 position 设置为 0。
|
||||
|
||||

|
||||

|
||||
|
||||
4\. <EFBFBD>ӻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ 4 <20><><EFBFBD>ֽڵ<D6BD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD>ʱ position <EFBFBD><EFBFBD>Ϊ 4<><34>
|
||||
4\. 从缓冲区中取 4 个字节到输出缓冲中,此时 position 设为 4。
|
||||
|
||||

|
||||

|
||||
|
||||
5\. <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> clear() <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ position <EFBFBD><EFBFBD> limit <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD>á<EFBFBD>
|
||||
5\. 最后需要调用 clear() 方法来清空缓冲区,此时 position 和 limit 都被设置为最初位置。
|
||||
|
||||

|
||||

|
||||
|
||||
## 4. <EFBFBD><EFBFBD>д<EFBFBD>ļ<EFBFBD>ʵ<EFBFBD><EFBFBD>
|
||||
## 4. 读写文件实例
|
||||
|
||||
1\. ΪҪ<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> FileInputStream<EFBFBD><EFBFBD>֮<EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD> FileInputStream <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> FileChannel<EFBFBD><EFBFBD>
|
||||
1\. 为要读取的文件创建 FileInputStream,之后通过 FileInputStream 获取输入 FileChannel;
|
||||
|
||||
```java
|
||||
FileInputStream fin = new FileInputStream("readandshow.txt");
|
||||
FileChannel fic = fin.getChannel();
|
||||
```
|
||||
|
||||
2\. <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ 1024 <EFBFBD><EFBFBD> Buffer
|
||||
2\. 创建一个容量为 1024 的 Buffer
|
||||
|
||||
```java
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1024);
|
||||
```
|
||||
|
||||
3\. <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> FileChannel д<EFBFBD>뵽 Buffer <EFBFBD>У<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵĻ<EFBFBD><EFBFBD><EFBFBD> read() <20><><EFBFBD><EFBFBD><EFBFBD>᷵<EFBFBD><E1B7B5> -1
|
||||
3\. 将数据从输入 FileChannel 写入到 Buffer 中,如果没有数据的话, read() 方法会返回 -1
|
||||
|
||||
```java
|
||||
int r = fcin.read(buffer);
|
||||
@ -249,86 +250,86 @@ if (r == -1) {
|
||||
}
|
||||
```
|
||||
|
||||
4\. ΪҪд<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> FileOutputStream<EFBFBD><EFBFBD>֮<EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD> FileOutputStream <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> FileChannel
|
||||
4\. 为要写入的文件创建 FileOutputStream,之后通过 FileOutputStream 获取输出 FileChannel
|
||||
|
||||
```java
|
||||
FileOutputStream fout = new FileOutputStream("writesomebytes.txt");
|
||||
FileChannel foc = fout.getChannel();
|
||||
```
|
||||
|
||||
5\. <EFBFBD><EFBFBD><EFBFBD><EFBFBD> flip() <EFBFBD>л<EFBFBD><EFBFBD><EFBFBD>д
|
||||
5\. 调用 flip() 切换读写
|
||||
|
||||
```java
|
||||
buffer.flip();
|
||||
```
|
||||
|
||||
6\. <EFBFBD><EFBFBD> Buffer <EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݶ<EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> FileChannel <EFBFBD><EFBFBD>
|
||||
6\. 把 Buffer 中的数据读取到输出 FileChannel 中
|
||||
|
||||
```java
|
||||
foc.write(buffer);
|
||||
```
|
||||
|
||||
7\. <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> clear() <EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
7\. 最后调用 clear() 重置缓冲区
|
||||
|
||||
```java
|
||||
buffer.clear();
|
||||
```
|
||||
|
||||
## 5. <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
## 5. 阻塞与非阻塞
|
||||
|
||||
Ӧ<EFBFBD><EFBFBD>ע<EFBFBD>⣬FileChannel <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Channel <EFBFBD><EFBFBD><EFBFBD>ԡ<EFBFBD>
|
||||
应当注意,FileChannel 不能切换到非阻塞模式,套接字 Channel 可以。
|
||||
|
||||
### 5.1 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ I/O
|
||||
### 5.1 阻塞式 I/O
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ I/O <20>ڵ<EFBFBD><DAB5><EFBFBD> InputStream.read() <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>һֱ<EFBFBD>ȵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>Ż᷵<EFBFBD>أ<EFBFBD><EFBFBD>ڵ<EFBFBD><EFBFBD><EFBFBD> ServerSocket.accept() <20><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>Ҳ<EFBFBD><D2B2>һֱ<D2BB><D6B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>пͻ<D0BF><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӲŻ᷵<C5BB>أ<EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӹ<EFBFBD><D3B9><EFBFBD><EFBFBD><EFBFBD><F3A3ACB7><EFBFBD><EFBFBD>˶<EFBFBD><CBB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>߳<EFBFBD>ȥ<EFBFBD><C8A5><EFBFBD><EFBFBD><EFBFBD>ÿͻ<C3BF><CDBB>˵<EFBFBD><CBB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
阻塞式 I/O 在调用 InputStream.read() 方法时会一直等到数据到来时(或超时)才会返回,在调用 ServerSocket.accept() 方法时,也会一直阻塞到有客户端连接才会返回,每个客户端连接过来后,服务端都会启动一个线程去处理该客户端的请求。
|
||||
|
||||

|
||||

|
||||
|
||||
### 5.2 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ I/O
|
||||
### 5.2 非阻塞式 I/O
|
||||
|
||||
<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>ר<EFBFBD>ŵ<EFBFBD><EFBFBD>߳<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD> I/O <20>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>
|
||||
由一个专门的线程来处理所有的 I/O 事件,并负责分发。
|
||||
|
||||
<EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƣ<EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD>
|
||||
事件驱动机制:事件到的时候触发,而不是同步的去监视事件。
|
||||
|
||||
<EFBFBD>߳<EFBFBD>ͨ<EFBFBD>ţ<EFBFBD><EFBFBD>߳<EFBFBD>֮<EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD> wait()<EFBFBD><EFBFBD>notify() <EFBFBD>ȷ<EFBFBD>ʽͨ<EFBFBD>ţ<EFBFBD><EFBFBD><EFBFBD>֤ÿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ν<EFBFBD><EFBFBD><EFBFBD>߳<EFBFBD><EFBFBD>л<EFBFBD><EFBFBD><EFBFBD>
|
||||
线程通信:线程之间通过 wait()、notify() 等方式通信,保证每次上下文切换都是有意义的,减少无谓的线程切换。
|
||||
|
||||

|
||||

|
||||
|
||||
## 6. <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD>
|
||||
## 6. 套接字实例
|
||||
|
||||
### 6.1 ServerSocketChannel
|
||||
|
||||
ÿһ<EFBFBD><EFBFBD><EFBFBD>˿ڶ<EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> ServerSocketChannel <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӡ<EFBFBD>
|
||||
每一个端口都需要有一个 ServerSocketChannel 用来监听连接。
|
||||
|
||||
```java
|
||||
ServerSocketChannel ssc = ServerSocketChannel.open();
|
||||
ssc.configureBlocking(false); // <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
ssc.configureBlocking(false); // 设置为非阻塞
|
||||
|
||||
ServerSocket ss = ssc.socket();
|
||||
InetSocketAddress address = new InetSocketAddress(ports[i]);
|
||||
ss.bind(address); // <EFBFBD>˿ں<EFBFBD>
|
||||
ss.bind(address); // 绑定端口号
|
||||
```
|
||||
|
||||
### 6.2 Selectors
|
||||
|
||||
<EFBFBD>첽 I/O ͨ<EFBFBD><EFBFBD> Selector ע<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ض<EFBFBD> I/O <20>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>Ȥ <20>D <20>ɶ<EFBFBD><C9B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵĵ<DDB5><C4B5><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><D7BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵȵȣ<C8B5><C8A3>ڷ<EFBFBD><DAB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>ʱ<EFBFBD><CAB1>ϵͳ<CFB5><CDB3><EFBFBD>ᷢ<EFBFBD><E1B7A2>֪ͨ<CDA8><D6AA>
|
||||
异步 I/O 通过 Selector 注册对特定 I/O 事件的兴趣 ― 可读的数据的到达、新的套接字连接等等,在发生这样的事件时,系统将会发送通知。
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> Selectors ֮<EFBFBD>Ϳ<EFBFBD><EFBFBD>ԶԲ<EFBFBD>ͬ<EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> register() <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>register() <EFBFBD>ĵ<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Selector<6F><72><EFBFBD>ڶ<EFBFBD><DAB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> OP_ACCEPT<50><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD> accept <20>¼<EFBFBD><C2BC><EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD>ӽ<EFBFBD><D3BD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>
|
||||
创建 Selectors 之后,就可以对不同的通道对象调用 register() 方法。register() 的第一个参数总是这个 Selector。第二个参数是 OP_ACCEPT,这里它指定我们想要监听 accept 事件,也就是在新的连接建立时所发生的事件。
|
||||
|
||||
SelectionKey <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD> Selector <20>ϵ<EFBFBD><CFB5><EFBFBD><EFBFBD><EFBFBD>ע<EFBFBD>ᡣ<EFBFBD><E1A1A3>ij<EFBFBD><C4B3> Selector ֪ͨ<CDA8><D6AA>ij<EFBFBD><C4B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD>ṩ<EFBFBD><E1B9A9>Ӧ<EFBFBD>ڸ<EFBFBD><DAB8>¼<EFBFBD><C2BC><EFBFBD> SelectionKey <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>еġ<EFBFBD>SelectionKey <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ע<EFBFBD>ᡣ
|
||||
SelectionKey 代表这个通道在此 Selector 上的这个注册。当某个 Selector 通知您某个传入事件时,它是通过提供对应于该事件的 SelectionKey 来进行的。SelectionKey 还可以用于取消通道的注册。
|
||||
|
||||
```java
|
||||
Selector selector = Selector.open();
|
||||
SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT);
|
||||
```
|
||||
|
||||
### 6.3 <EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD>
|
||||
### 6.3 主循环
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD>ȣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǵ<EFBFBD><EFBFBD><EFBFBD> Selector <EFBFBD><EFBFBD> select() <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ע<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߸<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD> select() <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
首先,我们调用 Selector 的 select() 方法。这个方法会阻塞,直到至少有一个已注册的事件发生。当一个或者更多的事件发生时, select() 方法将返回所发生的事件的数量。
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǵ<EFBFBD><EFBFBD><EFBFBD> Selector <EFBFBD><EFBFBD> selectedKeys() <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ط<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD> SelectionKey <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> <20><><EFBFBD><EFBFBD> <20><>
|
||||
接下来,我们调用 Selector 的 selectedKeys() 方法,它返回发生了事件的 SelectionKey 对象的一个 集合 。
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SelectionKeys <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD>ÿ<EFBFBD><EFBFBD> SelectionKey <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ÿһ<EFBFBD><EFBFBD> SelectionKey<65><79><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȷ<EFBFBD><C8B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʲô I/O <20>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>Լ<EFBFBD><D4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD><EFBFBD>Щ I/O <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
我们通过迭代 SelectionKeys 并依次处理每个 SelectionKey 来处理事件。对于每一个 SelectionKey,您必须确定发生的是什么 I/O 事件,以及这个事件影响哪些 I/O 对象。
|
||||
|
||||
```java
|
||||
int num = selector.select();
|
||||
@ -342,9 +343,9 @@ while (it.hasNext()) {
|
||||
}
|
||||
```
|
||||
|
||||
### 6.4 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
### 6.4 监听新连接
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǽ<EFBFBD>ע<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ServerSocketChannel<65><6C><EFBFBD><EFBFBD><EFBFBD>ҽ<EFBFBD>ע<EFBFBD><D7A2><EFBFBD><EFBFBD><EFBFBD>ǡ<EFBFBD><C7A1><EFBFBD><EFBFBD>ա<EFBFBD><D5A1>¼<EFBFBD><C2BC><EFBFBD>Ϊȷ<CEAA><C8B7><EFBFBD><EFBFBD>һ<EFBFBD>㣬<EFBFBD><E3A3AC><EFBFBD>Ƕ<EFBFBD> SelectionKey <EFBFBD><EFBFBD><EFBFBD><EFBFBD> readyOps() <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鷢<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʲô<EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD>
|
||||
程序执行到这里,我们仅注册了 ServerSocketChannel,并且仅注册它们“接收”事件。为确认这一点,我们对 SelectionKey 调用 readyOps() 方法,并检查发生了什么类型的事件:
|
||||
|
||||
```java
|
||||
if ((key.readyOps() & SelectionKey.OP_ACCEPT)
|
||||
@ -354,39 +355,39 @@ if ((key.readyOps() & SelectionKey.OP_ACCEPT)
|
||||
}
|
||||
```
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD>Կ϶<EFBFBD><EFBFBD><EFBFBD>˵<EFBFBD><EFBFBD> readOps() <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǹ<EFBFBD><C7B8>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD>ӡ<EFBFBD>
|
||||
可以肯定地说, readOps() 方法告诉我们该事件是新的连接。
|
||||
|
||||
### 6.5 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
### 6.5 接受新的连接
|
||||
|
||||
<EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>֪<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵȴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Կ<EFBFBD><EFBFBD><EFBFBD>ȫ<EFBFBD>ؽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>˵<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD><EFBFBD><EFBFBD> accept() <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
因为我们知道这个服务器套接字上有一个传入连接在等待,所以可以安全地接受它;也就是说,不用担心 accept() 操作会阻塞:
|
||||
|
||||
```java
|
||||
ServerSocketChannel ssc = (ServerSocketChannel)key.channel();
|
||||
SocketChannel sc = ssc.accept();
|
||||
```
|
||||
|
||||
<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ǽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD> SocketChannel <20><><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ġ<EFBFBD><C4A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڽ<EFBFBD><DABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD>Ϊ<EFBFBD>˶<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><D7BD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>ݣ<EFBFBD><DDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǻ<EFBFBD><C7BB><EFBFBD><EFBFBD>뽫 SocketChannel ע<EFBFBD>ᵽ Selector<EFBFBD>ϣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD>
|
||||
下一步是将新连接的 SocketChannel 配置为非阻塞的。而且由于接受这个连接的目的是为了读取来自套接字的数据,所以我们还必须将 SocketChannel 注册到 Selector上,如下所示:
|
||||
|
||||
```java
|
||||
sc.configureBlocking( false );
|
||||
SelectionKey newKey = sc.register( selector, SelectionKey.OP_READ );
|
||||
```
|
||||
|
||||
ע<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD> register() <EFBFBD><EFBFBD> OP_READ <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SocketChannel ע<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ȡ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ӡ<EFBFBD>
|
||||
注意我们使用 register() 的 OP_READ 参数,将 SocketChannel 注册用于 读取 而不是 接受 新连接。
|
||||
|
||||
### 6.6 ɾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SelectionKey
|
||||
### 6.6 删除处理过的 SelectionKey
|
||||
|
||||
<EFBFBD>ڴ<EFBFBD><EFBFBD><EFBFBD> SelectionKey ֮<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Է<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ˡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>DZ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƚ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SelectionKey <20><>ѡ<EFBFBD><D1A1><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD><C3B4><EFBFBD><EFBFBD>Ȼ<EFBFBD><C8BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>֣<EFBFBD><D6A3><EFBFBD><EFBFBD>ᵼ<EFBFBD><E1B5BC><EFBFBD><EFBFBD><EFBFBD>dz<EFBFBD><C7B3><EFBFBD><EFBFBD>ٴδ<D9B4><CEB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǵ<EFBFBD><C7B5>õ<EFBFBD><C3B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> remove() <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SelectionKey<EFBFBD><EFBFBD>
|
||||
在处理 SelectionKey 之后,我们几乎可以返回主循环了。但是我们必须首先将处理过的 SelectionKey 从选定的键集合中删除。如果我们没有删除处理过的键,那么它仍然会在主集合中以一个激活的键出现,这会导致我们尝试再次处理它。我们调用迭代器的 remove() 方法来删除处理过的 SelectionKey:
|
||||
|
||||
```java
|
||||
it.remove();
|
||||
```
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD><EFBFBD>Է<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܴ<EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> I/O <20>¼<EFBFBD>)<29>ˡ<EFBFBD>
|
||||
现在我们可以返回主循环并接受从一个套接字中传入的数据(或者一个传入的 I/O 事件)了。
|
||||
|
||||
### 6.7 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> I/O
|
||||
### 6.7 传入的 I/O
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ᴥ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> I/O <20>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ᵼ<EFBFBD><E1B5BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD>е<EFBFBD><D0B5><EFBFBD> Selector.select()<29><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>߶<EFBFBD><DFB6><EFBFBD> I/O <20>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>Σ<EFBFBD> SelectionKey <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ OP_READ <20>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE>
|
||||
当来自一个套接字的数据到达时,它会触发一个 I/O 事件。这会导致在主循环中调用 Selector.select(),并返回一个或者多个 I/O 事件。这一次, SelectionKey 将被标记为 OP_READ 事件,如下所示:
|
||||
|
||||
```java
|
||||
} else if ((key.readyOps() & SelectionKey.OP_READ)
|
||||
@ -398,9 +399,9 @@ it.remove();
|
||||
```
|
||||
|
||||
|
||||
# <EFBFBD>ο<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
# 参考资料
|
||||
|
||||
- Eckel B, <EFBFBD><EFBFBD><EFBFBD>˶<EFBFBD> , <20><><EFBFBD><EFBFBD> , <EFBFBD><EFBFBD> . Java <EFBFBD><EFBFBD><EFBFBD><EFBFBD>˼<EFBFBD><EFBFBD> [M]. <20><>е<EFBFBD><D0B5>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD> , 2002.
|
||||
- [IBM: NIO <EFBFBD><EFBFBD><EFBFBD><EFBFBD>](https://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html)
|
||||
- [ <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Java I/O <EFBFBD>Ĺ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ](https://www.ibm.com/developerworks/cn/java/j-lo-javaio/index.html)
|
||||
- [NIO <EFBFBD>봫ͳ IO <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ](http://blog.csdn.net/shimiso/article/details/24990499)
|
||||
- Eckel B, 埃克尔 , 昊鹏 , 等 . Java 编程思想 [M]. 机械工业出版社 , 2002.
|
||||
- [IBM: NIO 入门](https://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html)
|
||||
- [ 深入分析 Java I/O 的工作机制 ](https://www.ibm.com/developerworks/cn/java/j-lo-javaio/index.html)
|
||||
- [NIO 与传统 IO 的区别 ](http://blog.csdn.net/shimiso/article/details/24990499)
|
||||
|
Reference in New Issue
Block a user