NIO核心知识(区别、Channel、Buffer、Selector、SelectionKey、完整代码案例)

NIO核心知识

注:图片转载于并发编程网,链接:http://ifeve.com/。

0、IO和NIO的区别
①Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。
②Java IO的各种流是阻塞的。Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。
③Java NIO还提供Selector选择器,使得单线程更容易管理多个连接(多个通道的多个监听事件)。



1、Channel
Channel:翻译为通道,是一个接口,提供通道的实现规范。
作用:一个用于输入/输出操作的连接。通道表示一个实体的开放连接,例如硬件设备、文件、网络套接字或可以使用的程序组件执行一个或多个不同的输入/输出操作,例如读取或写操作。一般来说,通道是安全的,用于多线程访问。
实现类:FileChannel、SocketChannel、ServerSocketChannel、DatagramChannelChannel。

核心方法:
服务端
//打开通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
客户端
//打开通道
SocketChannel socketChannel = SocketChannel.open();



2、Buffer
Buffer:缓存区,是一个抽象类,提供实现不同数据类型缓存区的实现规范。
作用:Buffer用于与NIO通道进行交互,数据是从通道读入到缓冲区,从缓冲区写入通道的。
实现类:ByteBuffer、MappedByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer。

核心方法:
ByteBuffer byteBuffer = ByteBuffer.allocate(buffer_size);
byteBuffer.put(byteArray);

核心属性:
position:当前游标
limit:游标限制
capacity:容量
NIO核心知识(区别、Channel、Buffer、Selector、SelectionKey、完整代码案例)_第1张图片

查看源码
//将position设回0,可以重读Buffer中的所有数据。
public final Buffer rewind() {
    position = 0;
    mark = -1;
    return this;
}
//clear方法将缓冲区清空,在重新写缓冲区时调用。
public final Buffer clear() {
    position = 0;
    limit = capacity;
    mark = -1;
    return this;
}
//反转缓冲区,在准备从缓冲区中读取数据时调用flip方法。
public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
}

NIO核心知识(区别、Channel、Buffer、Selector、SelectionKey、完整代码案例)_第2张图片



3、Selector
Selector是通道监测器,能监测多个通道(Channel)的多个监听事件。

核心方法:
//获取通道监测器
Selector selector = Selector.open();
//监听
select();//阻塞到至少有一个通道在你注册的事件上就绪了。
select(long timeout);//和select()一样,除了最长会阻塞timeout毫秒(参数)。
selectNow();不会阻塞,不管什么通道就绪都立刻返回。
NIO核心知识(区别、Channel、Buffer、Selector、SelectionKey、完整代码案例)_第3张图片



4、SelectionKey
监听事件集合。

核心属性:
public static final int OP_READ = 1 << 0;
public static final int OP_WRITE = 1 << 2;
public static final int OP_CONNECT = 1 << 3;
public static final int OP_ACCEPT = 1 << 4;

核心方法:
//通道注册监听事件到通道监测器
channel.register(selector, SelectionKey.OP_READ);
//如何注册多个监听事件呢?
channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
//轮询就绪事件
while(iterator.hasNext()) {
	SelectionKey selectionKey = iterator.next();
	//略...
	iterator.remove();
}



5、完整代码案例

具体步骤:
1、服务端进入监听状态
2、客户端连接服务端,连接成功后向服务端发送消息
3、服务端接受到数据后,向客户端发送消息

服务端:
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;

/**
* @author 周杰
* @time 2017年10月25日 下午2:53:37
*/
public class Server {
	private static final int port = 12345;
	private static final int buffer_size = 1024;
	private static final String charsetName = "UTF-8";
	private static final String hello_message = "hello client !";
	public static void main(String[] args) throws Exception {
		//获取通道
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.configureBlocking(false);
		serverSocketChannel.bind(new InetSocketAddress(port));
		//获取通道管理器
		Selector selector = Selector.open();
		//将通道注册通道管理器的OP_ACCEPT事件
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		
		while(true) {
			//当有注册事件到达时,方法返回,否则阻塞
			selector.select();
			Iterator iterator = selector.selectedKeys().iterator();
			while(iterator.hasNext()) {
				SelectionKey selectionKey = iterator.next();
				if(!selectionKey.isValid()) {
					continue;
				}
				if(selectionKey.isAcceptable()) {
					System.out.println("accept a connection...");
					ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
					SocketChannel sc = ssc.accept();
					sc.configureBlocking(false);
					sc.register(selector, SelectionKey.OP_READ);
				}else if(selectionKey.isReadable()) {
					System.out.println("accept a message...");
					SocketChannel sc = (SocketChannel) selectionKey.channel();
					ByteBuffer byteBuffer = ByteBuffer.allocate(buffer_size);
					int length = sc.read(byteBuffer);
					if(length > 0) {
						String receive_message = new String(byteBuffer.array(), charsetName);
						System.out.println("server accept : "+receive_message);
						sc.write(ByteBuffer.wrap(hello_message.getBytes(charsetName)));
					}
				}
				iterator.remove();
			}
		}
	}
}




客户端:
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

/**
* @author 周杰
* @time 2017年10月25日 下午3:10:49
*/
public class Client {
	private static final int port = 12345;
	private static final int buffer_size = 1024;
	private static final String charsetName = "UTF-8";
	private static final String hello_message = "hello server !";
	public static void main(String[] args) throws Exception {
		//获取通道
		SocketChannel socketChannel = SocketChannel.open();
		socketChannel.configureBlocking(false);
		//获取通道管理器
		Selector selector = Selector.open();
		//连接
		socketChannel.connect(new InetSocketAddress(InetAddress.getLocalHost(), port));
		//将通道注册通道管理器的OP_CONNECT事件
		socketChannel.register(selector, SelectionKey.OP_CONNECT);
		while(true) {
			selector.select();
			for (SelectionKey key : selector.selectedKeys()) {
				if(!key.isValid()) {
					continue;
				}
				if(key.isConnectable()) {
					System.out.println("connect successfully...");
					SocketChannel sc = (SocketChannel) key.channel();
					if(sc.isConnectionPending()) {
						sc.finishConnect();
					}
					sc.register(selector, SelectionKey.OP_READ);
					sc.write(ByteBuffer.wrap(hello_message.getBytes(charsetName)));
				}else if(key.isReadable()) {
					System.out.println("accept a message...");
					SocketChannel sc = (SocketChannel) key.channel();
					ByteBuffer byteBuffer = ByteBuffer.allocate(buffer_size);
					int length = sc.read(byteBuffer);
					if(length > 0) {
						String receive_message = new String(byteBuffer.array(), charsetName);
						System.out.println("client accept : "+receive_message);
					}
				}
			}
		}
	}
}


你可能感兴趣的:(NIO核心知识(区别、Channel、Buffer、Selector、SelectionKey、完整代码案例))