BIO NIO AIO 的区别

首先要了解 阻塞非阻塞 同步异步

同步异步:

同步:是指发发送的一个消息 一个请求 需要对面返回 一个消息或者一个状态! 如果没有返回需要一直等待返回

异步:异步调用请求发送后,调用者无需等待消息返回便可进行其他操作,消息会以通知的方式告知调用者 就比如 你发送个微信 不需要立马回复 等一段时间 或者 等对方心情好在回复(添狗)

阻塞非阻塞:

阻塞:当前消息请求发送 没有结构返回 那么 当前线程会被挂起 直至返回消息

非阻塞:不能立刻得到结果之前,该调用不会阻塞当前线程!想干别的还可以干

BIO:

BIO(Blocking I/O) 同步阻塞IO

JDK1.4之前唯一选择, 只有这一种IO模型

问题:

有多个客户端进行连接时, 如: client1, client2 进行连接, 由于client1先与服务端进行了连接, 此时服务端只能处理client1的请求, 什么时候client1处理完, 什么时候才能处理其他的请求, 服务端的线程一直处理client1的请求, 所以再有其他的请求, 是没有办法处理的TCP/IP底层使用的是BIO, 同步阻塞的IO, 发起请求后, 必须等待接收到响应之后, 代码才能继续向下执行, 并且服务端一个线程只能处理一个客户端的一个请求

解决办法 ;

package com.mcc.bio;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author mcc
 * @title: MyServer
 * @projectName WEAVER
 * @description: TODO
 * @date 2022/5/1116:36
 */
public class MyServer {
    public static void main(String[] args) {
        try {
            //1.创建ServerSocket, 自动监听指定的ip+port
            ServerSocket serverSocket = new ServerSocket(9999);
            System.out.println("等待客户端连接");
            for(;;){
                //2.阻塞等待客户端的连接
                Socket accept = serverSocket.accept();
                System.out.println("客户端连接了");
                System.out.println("等待接受客户端的消息");
                /* 一个客户端的请求, 服务端需要创建一个线程提供服务 */
                new Thread(() -> {
                    for(;;){
                        //3.同步阻塞接受客户端的消息
                        try {
                            InputStream inputStream = accept.getInputStream();
                            DataInputStream dataInputStream = new DataInputStream(inputStream);
                            System.out.println("接收到客户端消息: "+dataInputStream.readUTF());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
package com.mcc.bio;

import java.io.DataOutputStream;
import java.net.Socket;
import java.util.Scanner;

/**
 * @author mcc
 * @title: MyClient1
 * @projectName WEAVER
 * @description: TODO
 * @date 2022/5/1116:38
 */
public class MyClient1 {
    public static void main(String[] args) {
        try {
            //1.创建客户端Socket, 自动连接指定的ip+port
            Socket socket = new Socket("127.0.0.1", 9999);
            Scanner scanner = new Scanner(System.in);
            System.out.println("向服务端发送消息");
            for(;;){
                //向服务端输出
                DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
                String next = scanner.next();
                dataOutputStream.writeUTF("客户端1"+next);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

每个客户端需要对应服务端的一个子线程。 所以有多少个客户端, 服务端就需要创建多少个子线程。如果客户端特别多,几万甚至几百万,服务器端就需要有几万甚至几百万的子线程。 由于每个子线程都有自己的独立线程区,这么多子线程可能就产生内存不足等问题。而且这么多的子线程也需要进行调度, 切换, 销毁这也是非常消耗性能的

虽然可以解决一个服务端处理多个客户端,但是因为过多的子线程导致系统资源消耗过多,线程切换导致性能下降也是我们不得不需要考虑的问题

可以使用线程池,在一定程度上提升程序性能

NIO:

NIO称为New IO(新的IO)又称Non-Blocking IO(非阻塞IO)

NIO的特性就是同步非阻塞IO模型

优势:

使用nio解决了使用BIO服务端创建过多子线程产生内存不足, 这么多的子线程也需要进行调度, 切换, 销毁也是非常消耗性能的问题

问题解决:

package com.mcc.bio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author mcc
 * @title: MyNioServer
 * @projectName WEAVER
 * @description: TODO
 * @date 2022/5/1116:49
 */
public class MyNioServer {
    public static void main(String[] args) {
        try {
            //1.开启ServerSocketChannel管道
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            //2.设置为非阻塞
            serverSocketChannel.configureBlocking(false);
            //3.绑定ip与port
            serverSocketChannel.bind(new InetSocketAddress("127.0.0.1", 9999));
            //4.将ServerSocketChannel注册到Selector选择器中
            /*
             * 1.创建选择器
             * 2.监听管道的状态(服务端等待接受客户端的连接状态)
             * */
            Selector selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            while(true){
                //5.获取管道的状态, 没有状态阻塞
                selector.select();
                //6.获取所有事件的迭代器
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()){
                    //7.获取迭代器中的每一个状态
                    SelectionKey next = iterator.next();
                    //8.状态为成功接收到客户端时
                    if(next.isAcceptable()){
                        //9.接收客户端的连接
                        SocketChannel accept = serverSocketChannel.accept();
                        System.out.println("接收到了客户端的连接");
                        //10.设置为非阻塞
                        accept.configureBlocking(false);
                        //11.监听数据的读取状态(接收到消息时, 为该状态)
                        accept.register(selector, SelectionKey.OP_READ);
                    }
                    if(next.isReadable()){
                        /* 接收客户端消息 */
                        //12.获取客户端管道
                        SocketChannel socketChannel = (SocketChannel) next.channel();
                        //13.读取客户端发送的消息
                        ByteBuffer allocate = ByteBuffer.allocate(1024);
                        socketChannel.read(allocate);
                        byte[] array = allocate.array();
                        System.out.println(new String(array, 0, allocate.position()));
                        /* 向客户端发送的消息 */
                        socketChannel.write(ByteBuffer.wrap("在吗?".getBytes()));
                    }
                    //移除当前的事件防止重复处理
                    iterator.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
package com.mcc.bio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * @author mcc
 * @title: MyNioClient
 * @projectName WEAVER
 * @description: TODO
 * @date 2022/5/1116:53
 */
public class MyNioClient {
    public static void main(String[] args) throws IOException {
        try {
            //1.开启SocketChannel管道
            SocketChannel socketChannel = SocketChannel.open();
            //2.设置为非阻塞
            socketChannel.configureBlocking(false);
            //3.将管道注册到Selector(选择器)中
            /*
             * 1.参数一: 选择器
             * 2.参数二: 监听已经与服务端连接的状态
             * */
            Selector selector = Selector.open();
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
            //4.连接服务端
            socketChannel.connect(new InetSocketAddress("127.0.0.1", 9999));
            while(true) {
                //5.获取客户端的状态(有状态, 继续执行. 没有状态, 阻塞等待)
                selector.select();
                //6.获取所有状态的迭代器
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()){
                    //7.获取每一个状态
                    SelectionKey next = iterator.next();
                    //8.已经与服务端连接成功状态时
                    if(next.isConnectable()){
                        //9.正在连接中
                        if (socketChannel.isConnectionPending()) {
                            //10.设置为完成连接
                            socketChannel.finishConnect();
                        }
                        System.out.println("与服务端连接成功");
                        /* 11.向服务端发送一句话 */
                        socketChannel.write(ByteBuffer.wrap("客户端连接成功".getBytes()));
                        //12.监听读取的事件(服务端发送消息会被监听到)
                        socketChannel.register(selector, SelectionKey.OP_READ);
                    }
                    if(next.isReadable()){
                        /* 13.读取服务端消息 */
                        ByteBuffer allocate = ByteBuffer.allocate(1024);
                        socketChannel.read(allocate);
                        byte[] array = allocate.array();
                        System.out.println(new String(array, 0, allocate.position()));
                        /* 14.向服务端发送消息 */
                        socketChannel.write(ByteBuffer.wrap("在".getBytes()));
                    }
                    //15.移除当前的事件防止重复处理
                    iterator.remove();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值