1.NIO提供了与传统BIO模型中的Socket和ServerSocket相对SocketChannelServerSocketChannel两种不同的套接字通道实现, 新增的着两种通道都支持阻塞和非阻塞两种模式。
2.缓冲区 Buffer,Buffer是一个对象,包含一些要写入或者读出的数据。 在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的;在写入数据时,也是写入到缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。缓冲区实际上是一个数组,并提供了对数据结构化访问以及维护读写位置等信息。
3.Selector一般称为选择器,也可以翻译为多路复用器,它是java Nio核心组件中的一个,用于检查一个或多个Nio Channel(通道)的状态是否处于可读,可写,如此可以实现单线程管理多个channels,也就是可以管理多个网络链接。
3.1. 使用Selector的好处在于:使用更少的线程就可以处理通道了,相比于使用多个线程,避免了线程上下文切换带来的开销。
代码部分:
import org.junit.Test;
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.Date;
import java.util.Iterator;
import java.util.Set;
public class SelectorDemo1 {
//客户端代码
@Test
public void clientDemo() throws Exception{
//1.获取通道,绑定主机和端口号
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",8180));
//2.切换到非堵塞模式
socketChannel.configureBlocking(false);
//3.创建buffer
ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
//4.写入buffer数据(写入当前时间)
writeBuffer.put(new Date().toString().getBytes());
//5.模式切换
writeBuffer.flip();
//6.写入通道
socketChannel.write(writeBuffer);
//7.关闭通道
socketChannel.close();
}
//服务端代码
@Test
public void serverDemo() throws IOException {
//1.获取服务端通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//2.切换非阻塞模式
serverSocketChannel.configureBlocking(false);
//3.绑定端口号
serverSocketChannel.bind(new InetSocketAddress(8180));
//4.获取selector选择器
Selector selector = Selector.open();
//5.通道注册到选择器上,进行监听
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
//6.选择器进行轮询,进行后续操作
while(selector.select()>0){
Set<SelectionKey> selectionKeys = selector.selectedKeys();
//遍历
Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
while(selectionKeyIterator.hasNext()){
SelectionKey next = selectionKeyIterator.next();
if(next.isAcceptable()){
//获取连接
SocketChannel accept = serverSocketChannel.accept();
//切换非阻塞模式
accept.configureBlocking(false);
//注册
accept.register(selector,SelectionKey.OP_READ);
}else if(next.isReadable()){
SocketChannel channel = (SocketChannel)next.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
//读取数据
int length = 0;
while((length = channel.read(readBuffer))>0){
readBuffer.flip();
System.out.println(new String(readBuffer.array(),0,length));
readBuffer.clear();
}
}
}
selectionKeyIterator.remove();
}
serverSocketChannel.close();
}
}
小结:
JAVA NIO:称为非阻塞IO,读写的过程中不会发生阻塞线程,我们之前所学习的流,称为BIO,阻塞是IO(通过accpet方法等待接收),就是在读写的过程中可能会发生阻塞现象。
非阻塞IO面向Channel("通道")的,不是面向Stream(流)的。
流的特点:方向单一,顺序读写。流要么是输入流用于顺序读取数据,要么是输出流用于顺序写出数据
Channel的特点:双向的,既可以读又可以写