文章目录
上一篇文章 介绍了传统网络编程在处理高并发和大规模应用时通常面临性能瓶颈和资源管理问题,而 NIO 通过非阻塞 I/O 和选择器机制提供了更高效的解决方案。虽然 NIO 的 API 更复杂,但在高负载和高性能需求的场景下,它能够显著改善传统阻塞 I/O 的不足。
这篇文章, 了解下NIO的基本开发:
在NIO中不再选择流的通信方式, 而是选择管道的方式.
每个客户端对应一个管道, 来自客户端的请求通过管道发给服务端.
NIO 为服务端在网络通信中引入了 Seletor , Seletor监控客户端的状态 , 使得服务端的有限线程充分复用起来.
NIO 有两个核心: Channel
和 Buffer
Channel简介
- Channel是IO通信的通道,类似于InputStream、OutputStream
- Channel没有方向性, 读取和写入都是用Channel
-
常见Channel
markdown1. 文件操作 FileChannel,读写文件中的数据。 2. 网络操作 SocketChannel,通过TCP读写网络中的数据。 ServerSockectChannel,监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。 DatagramChannel,通过UDP读写网络中的数据。
-
获得方式
markdown1. FileInputStreanm/FileOutputStream 2. RandomAccessFile 3. FileChannel.open(); 3. Socket 4. ServerSocket 5. DatagramSocket
Buffer简介
- Channel读取或者写入的数据,都要写到Buffer中,才可以被程序操作。
- 因为Channel没有方向性,所以Buffer为了区分读写,引入了读模式、写模式进行区分。
-
常见Buffer
markdown1. ByteBuffer 常用 2. CharBuffer 3. DoubleBuffer 4. FloatBuffer 5. IntBuffer 6. LongBuffer 7. ShortBuffer 8. MappedByteBuffer 是ByteBuffer的子类, 直接与内存打交道 (零拷贝相关)
-
获得方式
markdown1. ByteBuffer.allocate(10); // 一但分配空间,不可动态调整 2. encode()
-
写模式
①新创建 ②clean() ③compact
-
读模式
filp();
第一个NIO程序分析
NIO读取文件演示:
java
public static void main(String[] args) throws IOException {
// snow.txt 里写的是 hello netty
String filePath = "D:/BaiduNetdiskDownload/snow.txt";
// 创建 FileChannel
FileChannel fileChannel = new FileInputStream(filePath).getChannel();
// 创建buffer
ByteBuffer byteBuffer = ByteBuffer.allocate(15);
// 将数据读取进缓冲区
fileChannel.read(byteBuffer);
// byteBuffer 转换为读模式
byteBuffer.flip();
// 打印数据
while( byteBuffer.hasRemaining() ){
System.out.print((char) byteBuffer.get());
}
// 将 byteBuffer 重置为写模式
byteBuffer.clear();
}
上面的代码有个问题就是 , 当我的 snow.txt 里的数据大于 15 个字节的时候, 后面的数据是读取不到的.
改造上面的代码
java
public static void main(String[] args) throws IOException {
// snow.txt 里写的是 hello netty! study netty!
String filePath = "D:/BaiduNetdiskDownload/snow.txt";
// 创建 FileChannel
FileChannel fileChannel = new FileInputStream(filePath).getChannel();
// 创建buffer
ByteBuffer byteBuffer = ByteBuffer.allocate(15);
while ( true ){
// 将数据读取进缓冲区
int read = fileChannel.read(byteBuffer);
if( read == -1 ){
break;
}
// byteBuffer 转换为读模式
byteBuffer.flip();
// 打印数据
while( byteBuffer.hasRemaining() ){
System.out.print((char) byteBuffer.get());
}
// 将 byteBuffer 重置为写模式
byteBuffer.clear();
}
}
现在, 即使将 snow.txt 里的数据追加一些使其大于 15 字节, 也没有问题了.