BIO是传统的同步阻塞IO。对于一次读取IO的操作,数据并不会直接拷贝到程序缓冲区。通常包括两个不同阶段:
对于一个套接字上的输入操作,第一步通常涉及等待数据从网络中到达,当所有等待分组到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复制到应用程序缓冲区。
应用进程:负责收取消息
若数据没准备好,会一直阻塞。
来一个用户,起一个线程。
缺点:
NIO即I/O复用模型,是同步非阻塞模型。
NIO原理:应用进程去内核调用数据,用selector去帮助应用进程监听内核,如果数据准备好了,selector会通知应用进程有数据了,然后应用进程再去读取数据。
NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。
NIO包括三大组件:
NIO模型的核心,用来监听内核。
Selector与Channel是相互配合使用的,这些channel需要我们通过代码手动的注册到selector上,但此时Channel必须为非阻塞模式。
然后selector会监听所有的channel,一旦有事件发生,selector会通知用户,用户会根据监听到的事件类型做出不同的处理,
Selector可以监听Channel的四种状态(Connect、Accept、Read、Write),当监听到某一Channel的某个状态时,才允许对Channel进行相应的操作。
传统IO操作对read()或write()方法的调用,可能会因为没有数据可读/可写而阻塞,直到有数据响应。也就是说读写数据的IO调用,可能会无限期的阻塞等待,效率依赖网络传输的速度。最重要的是在调用一个方法前,无法知道是否会被阻塞。
NIO的Channel抽象了一个重要特征就是可以通过配置它的阻塞行为,来实现非阻塞式的通道。
serverSocketChannel.configureBlocking(false);//设置为非阻塞模式
Channel是一个双向通道,与传统IO操作只允许单向的读写不同的是,NIO的Channel允许在一个通道上进行读和写的操作。
客户端 服务器 都会对应一个自己的channel,并且这个channel是唯一的。
channel在发送数据的时候不能直接将数据本身进行发送,需要将数据放在buffer中,进行传输。
buffer–类似于数组,是NIO模型提供的一种数据结构,便于我们操作。
channel和buffer之间的关系:
buffer的分配:
对buffer对象的操作首先进行分配,buffer提供一个allocate(int capacity)方法分配一个指定字节大小的对象。
向buffer中写数据:
int bytes = channel.read(buf); //将channel中的数据读取到buf中
buf.put(byte); //将数据通过put()方法写入到buf中
flip()方法:
将Buffer从写模式切换到读模式,调用flip()方法会将position设置为0,并将limit设置为之前的position的值。
sendBuffer.clear();//每次要清空
SocketChannel client = (SocketChannel) selectionKey.channel();
String sendMsg = "Server recv hello";
sendBuffer.put(sendMsg.getBytes());//将信息放入buffer
sendBuffer.flip();//put后标志位发生改变,要将其移至首部
从buffer中读数据
client.write(sendBuffer);//将channel数据写入buffer中
byte bt = buf.get(); //从buf中读取一个byte