IO演化历程

阻塞(Block)

非阻塞(Non-Block)

IO类型

  • BIO 同步阻塞IO
同步异步针对请求,阻塞非阻塞针对客户端

客户端发送求情之后,一直等待服务端响应,客户端阻塞,请求,同步

在这里插入图片描述

//同步阻塞IO模型
public class BIOServer {
    
    

	//服务端网络IO模型的封装对象
	ServerSocket server;
	//服务器
	public BIOServer(int port){
    
    
		try {
    
    
			//Tomcat 默认端口8080
			//只要是Java写的都这么玩,3306
			//Redis  6379
			//Zookeeper  2181
			//HBase
			//RMI
			//TCP
			server = new ServerSocket(port);
			System.out.println("BIO服务已启动,监听端口是:" + port);
		} catch (IOException e) {
    
    
			e.printStackTrace();
		}
	}
	
	/**
	 * 开始监听,并处理逻辑
	 * @throws IOException 
	 */
	public void listen() throws IOException{
    
    
		//循环监听
		while(true){
    
    
			//等待客户端连接,阻塞方法
			//Socket数据发送者在服务端的引用
			Socket client = server.accept();
			System.out.println(client.getPort());

			//对方法数据给我了,读 Input
			InputStream is = client.getInputStream();

			//网络客户端把数据发送到网卡,机器所得到的数据读到了JVM内中
			byte [] buff = new byte[1024];
			int len = is.read(buff);
			if(len > 0){
    
    
				String msg = new String(buff,0,len);
				System.out.println("收到" + msg);
			}
		}
	}
	
	
	public static void main(String[] args) throws IOException {
    
    
		new BIOServer(8080).listen();
	}
	

public class BIOClient {
    
    

	public static void main(String[] args) throws UnknownHostException, IOException {
    
    

		//要和谁进行通信,服务器IP、服务器的端口
		//一台机器的端口号是有限
		Socket client = new Socket("localhost", 8080);

		//输出 O  write();
		//不管是客户端还是服务端,都有可能write和read

		OutputStream os = client.getOutputStream();

		//生成一个随机的ID
		String name = UUID.randomUUID().toString();

		System.out.println("客户端发送数据:" + name);
		//传说中的101011010
		os.write(name.getBytes());
		os.close();
		client.close();

		
	}
}
  • NIO 同步非阻塞IO
客户端发送求情之后,时不时过来检查服务端响应,客户端非阻塞,请求,同步

在这里插入图片描述

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;

/**
 * NIO的操作过于繁琐,于是才有了Netty
 * Netty就是对这一系列非常繁琐的操作进行了封装
 * <p>
 * Created by Tom.
 */
public class NIOServerDemo {
    
    

    private int port = 8080;

    //准备两个东西
    //轮询器 Selector 大堂经理
    private Selector selector;
    //缓冲区 Buffer 等候区
    private ByteBuffer buffer = ByteBuffer.allocate(1024);

    //初始化完毕
    public NIOServerDemo(int port) {
    
    
        //初始化大堂经理,开门营业
        try {
    
    
            this.port = port;
            ServerSocketChannel server = ServerSocketChannel.open();
            //我得告诉地址
            //IP/Port
            server.bind(new InetSocketAddress(this.port));
            //BIO 升级版本 NIO,为了兼容BIO,NIO模型默认是采用阻塞式
            server.configureBlocking(false);//设置为非阻塞

            //大堂经理准备就绪,接客
            selector = Selector.open();

            //在门口翻牌子,正在营业
            server.register(selector, SelectionKey.OP_ACCEPT);

        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

    public void listen() {
    
    
        System.out.println("listen on " + this.port + ".");
        try {
    
    
            //轮询主线程
            while (true) {
    
    
                //大堂经理再叫号
                selector.select();
                //每次都拿到所有的号子
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> iter = keys.iterator();
                //不断地迭代,就叫轮询
                //同步体现在这里,因为每次只能拿一个key,每次只能处理一种状态
                while (iter.hasNext()) {
    
    
                    SelectionKey key = iter.next();
                    //号子用完之后需要进行删除
                    iter.remove();
                    //每一个key代表一种状态
                    //没一个号对应一个业务
                    //数据就绪、数据可读、数据可写 等等等等
                    process(key);
                }

            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }

    //具体办业务的方法,坐班柜员
    //每一次轮询就是调用一次process方法,而每一次调用,只能干一件事
    //在同一时间点,只能干一件事
    private void process(SelectionKey key) throws IOException {
    
    
        //针对于每一种状态给一个反应
        if (key.isAcceptable()) {
    
    
            //数据就绪
            ServerSocketChannel server = (ServerSocketChannel) key.channel();
            //这个方法体现非阻塞,不管你数据有没有准备好
            //你给我一个状态和反馈
            SocketChannel channel = server.accept();
            //一定一定要记得设置为非阻塞
            channel.configureBlocking(false);
            //当数据准备就绪的时候,将状态改为可读
            key = channel.register(selector, SelectionKey.OP_READ);
        } else if (key.isReadable()) {
    
    
            //可读状态
            //key.channel 从多路复用器中拿到客户端的引用
            SocketChannel channel = (SocketChannel) key.channel();
            int len = channel.read(buffer);
            if (len > 0) {
    
    
                buffer.flip();
                String content = new String(buffer.array(), 0, len);
                key = channel.register(selector, SelectionKey.OP_WRITE);
                //在key上携带一个附件,一会再写出去
                key.attach(content);
                System.out.println("读取内容:" + content);
            }
        } else if (key.isWritable()) {
    
    
            //数据可写
            SocketChannel channel = (SocketChannel) key.channel();

            String content = (String) key.attachment();
            channel.write(ByteBuffer.wrap(("输出:" + content).getBytes()));

            channel.close();
        }
    }

    public static void main(String[] args) {
    
    
        new NIOServerDemo(8080).listen();
    }
}
  • AIO 异步阻塞IO
操作系统的性能决定AIO的性能 

客户端发送请求之后,去做别的事,等服务端给出响应之后,再过来处理业务逻辑

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44971379/article/details/121218470