一.简介
NIO(Non-blocking I/O,在Java领域,也称为New I/O),在jdk1.4 里提供的新api 。Sun 官方标榜的特性如下: 为所有的原始类型提供(Buffer)缓存支持,字符集编码解码解决方案。
Channel :一个新的原始I/O 抽象。 支持锁和内存映射文件的文件访问接口。 提供多路(non-bloking) 非阻塞式的高伸缩性网络I/O 。NIO也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,
成为解决高并发与大量连接、I/O处理问题的有效方式。
二.NIO的原理2.1 传统的IO的原理和弊端
使用传统的I/O程序读取文件内容, 并写入到另一个文件(或Socket), 如下程序:
[Java] 纯文本查看 复制代码
1
2
|
File.read(fileDesc, buf, len);
Socket.send(socket, buf, len);
|
会有较大的性能开销, 主要表现在一下两方面:
1. 上下文切换(context switch), 此处有4次用户态和内核态的切换
2. Buffer内存开销, 一个是应用程序buffer, 另一个是系统读取buffer以及socket buffer
其运行示意图如下
2. Buffer内存开销, 一个是应用程序buffer, 另一个是系统读取buffer以及socket buffer
其运行示意图如下
![](https://i-blog.csdnimg.cn/blog_migrate/29cd1954f9ab14f56939c66f143e583a.png)
1) 先将文件内容从磁盘中拷贝到操作系统buffer
2) 再从操作系统buffer拷贝到程序应用buffer
3) 从程序buffer拷贝到socket buffer
4) 从socket buffer拷贝到协议引擎.
传统BIO代码举例:
TraditionalClient.java
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.net.Socket;
public class TraditionalClient {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
// 创建socket链接
Socket socket = new Socket( "localhost" , 2000 );
System.out.println( "Connected with server " + socket.getInetAddress() + ":" + socket.getPort());
// 读取文件
FileInputStream inputStream = new FileInputStream( "C:/sss.txt" );
// 输出文件
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
// 缓冲区4096K
byte [] b = new byte [ 4096 ];
// 传输长度
long read = 0 ;
long total = 0 ;
// 读取文件,写到socketio中
while ((read = inputStream.read(b)) >= 0 ) {
total = total + read;
output.write(b);
}
// 关闭
output.close();
socket.close();
inputStream.close();
// 打印时间
System.out.println( "bytes send--" + total + " and totaltime--" + (System.currentTimeMillis() - start));
}
}
|
TraditionalServer.java
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
import java.io.DataInputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TraditionalServer {
public static void main(String args[]) throws Exception {
// 监听端口
ServerSocket server_socket = new ServerSocket( 2000 );
System.out.println( "等待,端口为:" + server_socket.getLocalPort());
while ( true ) {
// 阻塞接受消息
Socket socket = server_socket.accept();
// 打印链接信息
System.out.println( "新连接: " + socket.getInetAddress() + ":" + socket.getPort());
// 从socket中获取流
DataInputStream input = new DataInputStream(socket.getInputStream());
// 接收数据
byte [] byteArray = new byte [ 4096 ];
while ( true
|