一.常见IO模型
1.BIO
BIO是一种传统的同步阻塞的IO模型,每当有一个客户端发送IO请求时,服务端就要创建一个线程进行处理。当数据还未准备好时,当前线程会一直阻塞,占用CPU资源,造成资源浪费,如下图所示
BIO是基于流的形式来进行IO操作的,相较于NIO和AIO模型,在性能上相差较大。
2.NIO
NIO是同步非阻塞IO模型,它是基于缓冲区来实现的。核心主要包括三个部分:Channel、Buffer以及Selector。它会创建一个线程不断去轮询多个 socket 的状态,只有当 socket 真正有读写事件时,才真正调用实际的 IO 读写操作,也就是通过Selector来监听通道的事件,事件发生时,才会调用IO操作,不会造成阻塞。这样就能减少线程的开销以及资源浪费。在进行IO读写操作时,NIO 基于 Channel 和 Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中,如下图所示。
3.AIO
AIO是异步的IO模型,在异步 IO 模型中,当用户线程发起 read 操作之后,立刻就可以开始去做其它的事。从内核的角度来看,当它受到一个 异步 read 之后,它会立刻返回,说明 read 请求已经成功发起了,因此不会对用户线程产生任何 block。然后,内核会等待数据准备完成,然后将数据拷贝到用户线程,当这一切都完成之后,内核会给用户线程发送一个信号,告诉它 read 操作完成了。也就说用户线程完全不需要实际的整个 IO 操作是如何进行的,只需要先发起一个请求,当接收内核返回的成功信号时表示 IO 操作已经完成,可以直接去使用数据。
二.使用场景
1.BIO
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序简单易理解。
2.NIO
NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,弹幕系统,服务器间通讯等。编程比较复杂,JDK1.4开始支持。
3.AIO
AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
三.BIO编程
1.编码流程
1.构建BIO服务端,绑定对应端口
2.创建线程池来管理线程
3.等待客户端连接,通过serverSocket.accept()获取客户端socket
4.实现Runnable接口的run方法,实现数据的读写操作
5.通过telnet来进行测试
2.代码
public class BIOServer {
public static void main(String[] args) {
//1.创建线程池
ExecutorService executor = Executors.newCachedThreadPool();
//2.通过ServerSocket监听客户端连接,进行io操作
ServerSocket serverSocket = null;
try {
//绑定端口7777
serverSocket = new ServerSocket(7777);
} catch (IOException e) {
e.printStackTrace();
}
//3.轮询监听客户端连接,并执行io操作
while (true) {
try {
//等待客户端连接
final Socket socket = serverSocket.accept();
if(socket.isConnected()) {
executor.execute(new Runnable() {
public void run() {
try {
//通过字符流输出连接信息至客户端
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "GB2312"));
bw.write("已连接socketServer");
bw.flush();
//获取输入流,并转化成字符串输出
InputStream inputStream = socket.getInputStream();
byte[] buff = new byte[1024];
int len = 0;
while((len = inputStream.read(buff)) != -1) {
System.out.println(Thread.currentThread().getName() + " : " + new String(buff, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close(); //关闭socket
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.结果测试
通过命令行输入命令 telnet 127.0.0.1 7777 建立连接
然后输入 ctrl+】 进行文本输入模式
通过send命令发送消息至服务端