BIO/NIO/AIO
1.java的I/O演进之路
1.1 I/O的模型说明
- I/O模型: 也就是说用什么样的通道或者通信模式和架构进行数据的传输和接收,很大程度上解决了程序通信的性能,java共支持三种网络编程I/O模型:BIO/NIO/AIO
1.2 I/O模型
BIO
NIO
AIO
1.3 BIO/NIO/AIO使用场景
- BIO : 连接数目比较小且固定的架构,因为这种方法的服务器资源要求比较高,并发局限于应用中
- NIO : 连接数目比较多且连接比较短的架构,比如聊天室,弹幕系统
- AIO : 连接数目比较多且连接比较长的架构,比如相册服务器
2.BIO
2.1 BIO的介绍
2.2 BIO工作机制
-
实现客户端和服务器多发多收
public class Server { public static void main(String[] args) { try { // 定义socket对象对服务端端口注册 ServerSocket socket = new ServerSocket(9999); // 监听客户端socket连接请求 Socket accept = socket.accept(); // 从socket管道中得到字节输入流 InputStream is = accept.getInputStream(); // 包装成缓冲字符输入流 BufferedReader bis = new BufferedReader(new InputStreamReader(is)); String message; while ((message = bis.readLine()) != null) { System.out.println(message); } } catch (IOException e) { e.printStackTrace(); } } }
public class Client { public static void main(String[] args) throws IOException { // 创建socket对象请求服务端的连接 Socket socket = new Socket("localhost", 9999); // 从socket中获取一个字节输入流 OutputStream os = socket.getOutputStream(); // 把字节输入流包装成打印流 PrintStream ps = new PrintStream(os); Scanner sc = new Scanner(System.in); while (true) { System.out.println("请输入"); ps.println(sc.nextLine()); ps.flush(); } } }
2.3 BIO模式下接收多个客户端
public class Server {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(3);
try {
// 定义socket对象对服务端端口注册
ServerSocket socket = new ServerSocket(9999);
// 定义死循环 监听客户端socket连接请求
while (true) {
Socket accept = socket.accept();
pool.execute(() -> {
try {
// 从socket管道中得到字节输入流
InputStream is = accept.getInputStream();
// 包装成缓冲字符输入流
BufferedReader bis = new BufferedReader(new InputStreamReader(is));
String message;
while ((message = bis.readLine()) != null) {
System.out.println(message);
}
} catch (IOException e) {
e.printStackTrace();
}
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.4 BIO实现文件上传
public class Client {
public static void main(String[] args) {
try (
// jdk1.7以后资源释放的一种方式
InputStream is = new FileInputStream("/Users/liubo/typora/images/image-20220518194133028.png")
) {
// 请求与服务端socket连接
Socket socket = new Socket("localhost", 8888);
// 把字节输入流包装成数据输入流
DataOutputStream ds = new DataOutputStream(socket.getOutputStream());
// 先发送上传文件后缀给服务端
ds.writeUTF(".png");
// 把文件数据发送服务端
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) > 0) {
ds.write(buffer);
}
ds.flush();
socket.shutdownOutput(); // 通知服务端数据发送完成
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Slf4j(topic = "c.tes")
public class Server {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(3);
try {
// 定义socket对象对服务端端口注册
ServerSocket socket = new ServerSocket(8888);
while (true) {
Socket accept = socket.accept();
pool.execute(() -> {
try {
// 得到数据输入流获取客户端发来的数据
DataInputStream dos = new DataInputStream(accept.getInputStream());
// 读取客户端发来的文件类型
String fileType = dos.readUTF();
log.debug("服务器接收到文件文件类型为:{}", fileType);
// 定义一个字节输出管道将读取的数据写出去
OutputStream os = new FileOutputStream("/Users/liubo/a/" + UUID.randomUUID() + fileType);
// 把文件数据发送服务端
byte[] buffer = new byte[1024];
int len;
while ((len = dos.read(buffer)) > 0) {
os.write(buffer);
}
os.close();
log.debug("服务端接收文件保存成功");
} catch (Exception e) {
e.printStackTrace();
}
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.NIO
3.1 NIO的介绍
3.2 NIO和BIO比较
3.2 NIO的三大核心
3.3 NIO Buffer介绍
缓冲区
Buffer类及其子类
缓冲区的基本属性
buffer常见api
缓冲区数据操作
- 使用buffer读写数据一般的4个步骤
- 写入数据到buffer
- 调用filp方法切换到读模式
- 从buffer中读取数据
- 调用buffer.clear清除缓冲区
直接与非直接内存
3.4 NIO Channel
通道channel概述
常见chanel实现类
FileChannel类
// 写数据到文件
public class Test2 {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("1.txt");
FileChannel channel = fos.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
String name = "ha666";
buffer.put(name.getBytes());
buffer.flip();
channel.write(buffer);
channel.close();
}
}
// 读取文件中数据
public class Test3 {
public static void main(String[] args) throws IOException {
FileInputStream fos = new FileInputStream("1.txt");
FileChannel channel = fos.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);
buffer.flip();
String value = new String(buffer.array(), 0, buffer.remaining());
System.out.println(value);
}
}