BIO:阻塞式IO,我们传统的流式IO就是阻塞式IO,意思式在读写的过程中可能发生阻塞
NIO:非阻塞IO,读写过程中不会产生阻塞。
AIO:在NIO基础上完成异步非阻塞。 NIO属于同步非阻塞。
同步:单线程上执行的操作,执行存在先后顺序。
异步:多个线程执行的操作,执行没有先后顺序。
IO发生阻塞最常见的场景出现与网络上的IO操作。好比TCP连接中Socket产生IO阻塞。
之前使用流式IO完成TCP通讯式,只能依靠多线程来完成同时多客户端交互。
那么使用了NIO后,就可以以单线程形式完成上述操作。
好处:资源开销小,运行性能好。
缺点:NIO设计不够优雅。以后有了NIO知识后,可以学习netty框架。
NIO实现(复制文件)代码演示:
public class NIODemo {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("NARUTO.JPG");
FileOutputStream fos = new FileOutputStream("NARUTO_CP.JPG");
//通过流获取对应的NIO通道,用通道对文件进行读写操作
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel();
//创建一个10KB的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024*10);
int len;//记录每次实际读取到的字节数
while((len = inChannel.read(buffer))!=-1) {
buffer.flip();
outChannel.write(buffer);
buffer.clear();
}
System.out.println("复制完毕");
inChannel.close();
outChannel.close();
}
}
1.2 NIO缓存操作
读入数据装满空间 读入空间的一部分数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SQVWPDgB-1656237914892)(C:UserstarenaAppDataRoamingTyporatypora-user-imagesimage-20220626163953324.png)]
小项目体验IO与NIO区别:
服务端代码:
public class NIOServer {
//存放所有客户端Channel,便于广播消息
private List allChannel = new ArrayList<>();
public void start(){
try {
ServerSocketChannel serverSocketChannel
= ServerSocketChannel.open();
//需要显示的设置为非阻塞状态,必须为非阻塞状态才能交给多路选择器监控事件
serverSocketChannel.configureBlocking(false);
//打开服务端口8088,客户端就可以通过8088端口进行连接了
serverSocketChannel.bind(new InetSocketAddress(8088));
//创建一个多路选择器
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while(true) {
System.out.println("主线程等待多路选择提示是否有事件要处理...");
selector.select();//该方法会形成阻塞
System.out.println("多路选择器监听到有事件要进行处理!!");
//通过多路选择器将所有待处理的事件全部获取回来进行逐一处理
Set set = selector.selectedKeys();
//遍历每一个事件并进行对应处理
for (SelectionKey key : set) {
//使用分支判断该事件是什么事件,以便做对应的处理
//判断该事件是否为ServerSocketChannel中的accept事件(有客户端连接了)
if (key.isAcceptable()) {
//通过事件获取相关通道来进行对应的操作
//对于accept事件而言,只有ServerSocketChannel会触发。
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel socket = ssc.accept();//接电话
if (socket != null) {
//将当前SocketChannel存入共享集合
allChannel.add(socket);
//将该SocketChannel注册到多路选择上,让其监听发送消息过来的事件
socket.configureBlocking(false);//将SocketChannel设置为非阻塞的,这样才能交给多路选择器
socket.register(selector, SelectionKey.OP_READ);
}
//判断事件是否为有的通道上有消息可以读取(某个客户端发送消息过来了)
}else if(key.isReadable()){
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024*10);
int len = socketChannel.read(buffer);
if(len==-1){//客户端断开连接,服务端这里才会读取到-1
socketChannel.close();//断开连接
allChannel.remove(socketChannel);
}
buffer.flip();//position-limit之间就是刚刚读取到的数据了。
byte[] data = new byte[buffer.limit()];
buffer.get(data);//调用后data中保存的就是position-limit之间的数据
String line = new String(data, StandardCharsets.UTF_8);
System.out.println("客户端说:"+line);
//遍历allChannel集合,将消息发送给所有客户端
for(SocketChannel sc : allChannel){
buffer.flip();//limit=position,position=0
sc.write(buffer);//limit与position值相同了
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
NIOServer server = new NIOServer();
server.start();
}
}
客户端代码:
public class Client {
private Socket socket;
public Client(){
try {
System.out.println("正在连接服务端...");
socket = new Socket("localhost",8088);
System.out.println("已连接服务端!");
} catch (IOException e) {
e.printStackTrace();
}
}
public void start(){
try {
ServerHandler serverHandler = new ServerHandler();
Thread t = new Thread(serverHandler);
t.setDaemon(true);
t.start();
//低级流,通过该流写出的字节就发送给了远端计算机
OutputStream out = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8);
BufferedWriter bw = new BufferedWriter(osw);
PrintWriter pw = new PrintWriter(bw,true);
Scanner scanner = new Scanner(System.in);
while(true){
String line = scanner.nextLine();//获取控制台输入的一行字符串
if("exit".equalsIgnoreCase(line)){
break;//停止循环
}
pw.println(line);//将输入的内容发送给服务端
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//与服务端断开连接
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Client client = new Client();
client.start();
}
private class ServerHandler implements Runnable{
public void run() {
try{
InputStream in = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(isr);
String message;
while((message = br.readLine()) != null){
System.out.println(message);
}
}catch(IOException e){
}
}
}
}
BufferedReader br = new BufferedReader(isr);
String message;
while((message = br.readLine()) != null){
System.out.println(message);
}
}catch(IOException e){
}
}
}
}



