Java--NIO&&AIO

1 阻塞和非阻塞
阻塞和非阻塞是进程在访问数据的时候,数据内是否准备就绪的一种处理方式。
1.1 阻塞:当数据没有准备的时候,往往需要等待缓冲区中的数据准备好过后才处理其他的事情,否者一直等待在那里。
1.2 非阻塞:当我们的进程访问我们的数据缓冲区的时候,数据没有准备好的时候,直接返回,不需要等待,数据有的时候也直接返回。

2 同步和异步的方式:
同步:同步的方式在处理IO事件的时候,必须阻塞在某个方法上面等待我们的IO时间完成。
异步:所有的IO读写交给操作系统去处理,这个时候可以去做其他事情。并不需要去完成真正的IO操作。
当操作完成IO后,我们的应用程序一个通知就可以了。

	同步与异步是针对应用程序与内核的交互而言的。同步过程中进程触发IO操作并等待或者轮询的去查看IO操作是否完成。异步过程中进程触发IO操作以后,直接返回,做自己的事情,IO交给内核来处理,完成后内核通知进程IO完成。

阻塞与非阻塞
  应用进程请求I/O操作时,如果数据未准备好,如果请求立即返回就是非阻塞,不立即返回就是阻塞。简单说就是做一件事如果不能立即获得返回,需要等待,就是阻塞,否则就可以理解为非阻塞。
  同步和异步关注的是消息通信机制,阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
  同步和异步关注的是任务完成消息通知的机制,而阻塞和非阻塞关注的是等待任务完成时请求者的状态。
参考:
https://www.cnblogs.com/ZY-Dream/p/10146236.html

3 多路复用技术(select模式)
读写事件交给一个单独的线程来处理,完成IO事件的注册,还有就是不断的去轮询我们的读写缓冲区,
看是否有数据准备好,通知相应的读写线程,这样的话,以前的读写线程就可以做其他的事情。
这个时候阻塞的不是所有的IO线程,阻塞的是Select这个线程。

4 NIO:Select+非阻塞,同步非线程,原来的I/O以流的方式处理数据,而NIO以块的方式处理数据。
这里写图片描述

4.1 通过selector(选择器)就相当于管家,管理所有的IO事情。
执行open工厂方法创建一个新的ServerSocketChannel对象,将会返回一个未绑定的ServerSocket关联的通道。一个通道可以被注册到多个选择器上,但对每个选择器而言只能被注册一次。选择键封装了通道与选择器的注册关系。通道在被注册到一个选择器上之前,必须先设置为非阻塞模式。通过
调用configureBlocking(false).

// 获得一个socket通道
channel = SocketChannel.open();
// 获取 一个通道管理器
selector = Selector.open();
// 设置为非阻塞
channel.configureBlocking(false);
channel.register(this.selector, SelectionKey.OP_CONNECT);

4.2 Selector管理事件
当IO事件注册给我们的选择器的时候,选择器都会给他们分配一个key值,可以简单的理解成一个时间标签,当IO事件完成过通过key值来找到相应的管道,然后通过管道发送数据和接受数据。
4.3 使用非阻塞I/O编写服务器处理程序,大致的步骤为
1 向Selector对象注册感兴趣的事件
2 从Selector中获取感兴趣的事件
3 根据不同的事件进行相应的处理
4.4相关操作:
判断IO事件是否已经就绪:

key.isAccptable:是否可以接受客户端的连接
key.isconnctionable:是否可以了解服务端
key.isreadable();缓冲区是否可读
key.iswriteable();缓冲区是否可写。

获得事件的keys:

selecttionkey keys=Selector.selectedkeys();

注册:

channel.regist(Selector,Selectionkey.OP_Write);
channel.regist(Selector,Selectionkey.OP_Read);
channel.regist(Selector,SelectionKey.OP_Connct);
channel.regist(Selector,Selectionkey,OP_Accept);

案例–客户端与服务端直接的通信:
服务端流程图
这里写图片描述
服务端:

public class Server {

	private final static Integer blockSize = 4096;

	private ByteBuffer sendBuffer = ByteBuffer.allocate(blockSize);

	private ByteBuffer receiveBuffer = ByteBuffer.allocate(blockSize);

	private final static String HOSTNAME = "127.0.0.1";

	private final static Integer PORT = 7080;

	private final static InetSocketAddress SOCKET_ADDRESS = new InetSocketAddress(
			HOSTNAME, PORT);

	private Selector selector;

	public Server() throws IOException {
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.configureBlocking(false);
		ServerSocket serverSocket = serverSocketChannel.socket();
		// 绑定IP和端口
		serverSocket.bind(SOCKET_ADDRESS);
		// 打开选择器
		this.selector = Selector.open();
		// 注册
		serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);
		System.out.println("Server start->");
	}

	// 监听
	public void listen() throws IOException {
		System.out.println("开始监听。。。");
		while (true) {
			// 没有业务时,将会出现阻塞
			Integer key = this.selector.select();// 就绪的通道个数
			if (key > 0) {
				Set<SelectionKey> selectedKeys = this.selector.selectedKeys();
				Iterator<SelectionKey> iter = selectedKeys.iterator();
				while (iter.hasNext()) {
					SelectionKey selectionKey = iter.next();
					iter.remove();
					// 业务逻辑
					if (selectionKey.isAcceptable()) {// 连接事件
						acceptHandle(selectionKey);
					} else if (selectionKey.isReadable()) {// 读事件
						readHandle(selectionKey);
					} else if (selectionKey.isWritable()) {// 写事件
						writeHandle(selectionKey);
					}
				}
			}
		}
	}

	/**
	 * 接受事件处理
	 * 
	 * @param selectionKey
	 * @throws IOException
	 */
	private void acceptHandle(SelectionKey selectionKey) throws IOException {
		ServerSocketChannel server = (ServerSocketChannel) selectionKey
				.channel();
		// 获得和客户端连接的通道
		SocketChannel client = server.accept();
		client.configureBlocking(false);// 设置为非阻塞
		client.register(this.selector, SelectionKey.OP_READ);// 注册读事件
	}

	/**
	 * 读事件处理
	 * 
	 * @param selectionKey
	 * @throws IOException
	 */
	private void readHandle(SelectionKey selectionKey) throws IOException {
		SocketChannel client = (SocketChannel) selectionKey.channel();
		receiveBuffer.clear();// 将limit移动到capacity位置,将position移动到0的位置,添加数据做准备
		Integer number = client.read(receiveBuffer);// 读取数据
		if (number > 0) {
			String receiveText = new String(receiveBuffer.array(), 0, number);
			System.out.println("服务器----接收----》" + receiveText);
			client.register(this.selector, SelectionKey.OP_WRITE);// 注册写事件
		}
	}

	/**
	 * 写事件处理
	 * 
	 * @param selectionKey
	 * @throws IOException
	 */
	private void writeHandle(SelectionKey selectionKey) throws IOException {
		SocketChannel client = (SocketChannel) selectionKey.channel();
		String sendText = "Hello,Client";
		sendBuffer.clear();// 将limit移动到capacity位置,将position移动到0的位置,添加数据做准备
		sendBuffer.put(sendText.getBytes());
		sendBuffer.flip();// 将limit移动到position位置,将position位置,为出数据做准备
		client.write(sendBuffer);// 发送数据
		System.out.println("服务器----发送----》" + sendText);
		client.register(this.selector, SelectionKey.OP_READ);// 注册读事件
	}

	public static void main(String[] args) throws IOException {
		new Server().listen();
	}
}

这里写图片描述
客户端:

public class Client {
	private final static Integer blockSize = 4096;

	private final static String HOSTNAME = "127.0.0.1";

	private final static Integer PORT = 7080;

	private final static InetSocketAddress SOCKET_ADDRESS = new InetSocketAddress(
			HOSTNAME, PORT);

	private static ByteBuffer sendBuffer = ByteBuffer.allocate(blockSize);

	private static ByteBuffer receiveBuffer = ByteBuffer.allocate(blockSize);

	private Selector selector;

	public Client() throws IOException {
		SocketChannel socketChannel = SocketChannel.open();
		// 是否阻塞
		socketChannel.configureBlocking(false);
		this.selector = Selector.open();
		socketChannel.register(this.selector, SelectionKey.OP_CONNECT);
		socketChannel.connect(SOCKET_ADDRESS);
	}

	public void listen() throws IOException {
		System.out.println("客户端启动。。。");
		while (true) {
			int key = this.selector.select();// 就绪的通道个数
			if (key > 0) {
				Set<SelectionKey> selectionKeys = this.selector.selectedKeys();
				Iterator<SelectionKey> iterator = selectionKeys.iterator();
				while (iterator.hasNext()) {
					SelectionKey selectionKey = iterator.next();
					if (selectionKey.isConnectable()) {// 连接事件
						connectHandle(selectionKey);
					} else if (selectionKey.isReadable()) {// 读事件
						readHandle(selectionKey);
					} else if (selectionKey.isWritable()) {// 写事件
						writeHandle(selectionKey);
					}
				}
				selectionKeys.clear();
			}
		}
	}

	/**
	 * 连接事件处理
	 * 
	 * @param selectionKey
	 * @throws IOException
	 */
	private void connectHandle(SelectionKey selectionKey) throws IOException {
		System.out.println("client connect");
		SocketChannel client = (SocketChannel) selectionKey.channel();
		if (client.isConnectionPending()) {
			client.finishConnect();
			System.out.println("客户端完成连接操作");
			sendBuffer.clear();// 将limit移动到capacity位置,将position移动到0的位置,添加数据做准备
			sendBuffer.put("Hello,Server".getBytes());
			sendBuffer.flip();// 将limit移动到position位置,将position位置,为出数据做准备
			client.write(sendBuffer);
		}
		client.register(this.selector, SelectionKey.OP_READ);
	}

	/**
	 * 读事件处理
	 * 
	 * @param selectionKey
	 * @throws IOException
	 */
	private void readHandle(SelectionKey selectionKey) throws IOException {
		SocketChannel client = (SocketChannel) selectionKey.channel();
		receiveBuffer.clear();
		Integer number = client.read(receiveBuffer);
		if (number > 0) {
			String receiveText;
			receiveText = new String(receiveBuffer.array(), 0, number);
			System.out.println("客户端----接收----》" + receiveText);
			client.register(this.selector, SelectionKey.OP_WRITE);// 注册写事件
		}
	}

	/**
	 * 写事件处理
	 * 
	 * @param selectionKey
	 * @throws IOException
	 */
	private void writeHandle(SelectionKey selectionKey) throws IOException {
		SocketChannel client = (SocketChannel) selectionKey.channel();
		sendBuffer.clear();// 将limit移动到capacity位置,将position移动到0的位置,添加数据做准备
		String sendText = "客户端已收到消息";
		sendBuffer.put(sendText.getBytes());
		sendBuffer.flip();// 将limit移动到position位置,将position位置,为出数据做准备
		client.write(sendBuffer);
		System.out.println("客户端----发送----》" + sendText);
		client.register(this.selector, SelectionKey.OP_READ);// 注册读事件
	}

	public static void main(String[] args) throws IOException {
		new Client().listen();
	}
}

6 基于文件的NIO

public class FileChannelDemo {

	@SuppressWarnings({ "resource" })
	public static void fileChannelDemo() {
		try {
			ByteBuffer buff = ByteBuffer.allocate(1024);
			FileInputStream fileInputStream=new FileInputStream("d:/a.txt");
			// 通过文件输入流获取通道对象(读取操作)
			FileChannel inFc = fileInputStream.getChannel();

			// 追加写入文件
			FileChannel outFc = new FileOutputStream("d:/a.txt",true).getChannel();
			// 读取数据
			buff.clear();
			int len = inFc.read(buff);
			System.out.println(new String(buff.array(), 0, len));

			// 写数据
			ByteBuffer buf2 = ByteBuffer.wrap("789".getBytes());
			outFc.write(buf2);

			// 关闭资源
			outFc.close();
			inFc.close();
		} catch (Exception exception) {
			exception.printStackTrace();
		}
	}
	public static void main(String[] args) {
		fileChannelDemo();
		System.out.println("run over");
	}
}

7 AIO 异步非阻塞IO
这里写图片描述
案例–服务端与客户端之间的通信:
服务端:

package com.text.aio01;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ExecutionException;

public class AioServer {

	private static final String HOST_NAME = "127.0.0.1";

	private static final Integer PORT = 7080;

	private static final InetSocketAddress inetSocketAddress = new InetSocketAddress(
			HOST_NAME, PORT);

	public AioServer() throws Exception {
		final AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel
				.open();
		listener.bind(inetSocketAddress);// 绑定网络地址
		listener.accept(null,
				new CompletionHandler<AsynchronousSocketChannel, Void>() {
					@Override
					public void completed(AsynchronousSocketChannel ch, Void vi) {
						listener.accept(null, this);// 接收下一个连接
						handler(ch);
					}

					@Override
					public void failed(Throwable exc, Void vi) {
						System.out.println("异步IO失败");
					}
				});
	}

	public void handler(AsynchronousSocketChannel ch) {
		ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
		try {
			ch.read(byteBuffer).get();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		byteBuffer.flip();
		System.out.println("服务器接收到的数据" + byteBuffer.get());
	}

	public static void main(String[] args) {
		try {
			AioServer aioServer = new AioServer();
			Thread.sleep(10000);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

客户端:

package com.text.aio01;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.Future;

public class AioClient {

	private static final String HOST_NAME = "127.0.0.1";

	private static final Integer PORT = 7080;

	private static final InetSocketAddress SOCKET_ADDRESS = new InetSocketAddress(
			HOST_NAME, PORT);

	private AsynchronousSocketChannel client = null;

	public AioClient() throws Exception {
		client = AsynchronousSocketChannel.open();
		Future<?> future = client.connect(SOCKET_ADDRESS);
		System.out.println(future.get());
	}

	/**
	 * 写数据
	 * @param b
	 */
	public void write(byte b) {
		ByteBuffer byteBuffer = ByteBuffer.allocate(32);
		byteBuffer.put(b);
		byteBuffer.flip();
		client.write(byteBuffer);
	}

	public static void main(String[] args) throws Exception {
		AioClient aioClient = new AioClient();
		aioClient.write((byte) 11);
	}
}

附IO和NIO之间的比较。通过餐厅中服务员和客人之间的交互来形象说明。
IO:
这里写图片描述
NIO:
这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值