JAVA NIO
Java SE1.4引入了大量用于改进输入/输出处理机制的特性
NIO的特性:
1、字符集编码器和解码器
2、非阻塞的I/O
3、内存映射文件
4、文件加锁机制
大多数操作系统都可以利用虚拟内存实现将一个文件或者文件的一部分“映射”到内存中。然后就可以像内存一样访问快速。
JAVA NIO中提供了访问内存映射的方式“通道(channel)”传递,通道是用户磁盘文件的一种抽象,提供访问诸如内存映射、文件加锁机制以及文件间快速数据等操作系统特性。
谈谈:非阻塞IO几个组成部分
1、Buffer
ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer
2、Channel
FileChannel、DataGramaChannel、SocketChannel、ServerSocketChannel
3、CharSet
CharEncoder、CharDecoder
4、Selector
Selector运行单线程处理多个Channel,要使用Selector需要向它注册Channel。
Selector源码中它维护了一个集合(SelectionKey),它分别有以下状态:
//一个是已注册的registedKeys(它里面是SelectionKey集合)集合
//一个是已选择的selectedKeys集合
//一个是已取消但未解除注册的cancelledKeys集合
SelectionKey维护了两个对象(感兴趣时间、Channel)
//SelectionKey是channel和Selector的关联对象
//SelectionKey维护了两个Set集合,一个是感兴趣事件,一个是准备好并可以执行I/O操作的Channel
简单的例子
package nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.Iterator;
/**
*服务器端
*1、创建编码方式 CharSet
*2、创建Selector
*3、创建服务SocketChannel
*/
public class NioServer {
//服务器端口
int port=9999;
//编码器
CharsetEncoder encoder=Charset.forName("GB2312").newEncoder();
//解码器
CharsetDecoder decoder=Charset.forName("GB2312").newDecoder();
//通道选择器
Selector selector;
//服务器socket通道
ServerSocketChannel channel;
//缓存 指定数据块为1024
ByteBuffer buffer=ByteBuffer.allocate(1024);
/**
*
* 打开选择器
* @throws IOException
*/
public void initSelector() throws IOException{
selector=Selector.open();
}
/**
*
* 初始化服务器
* @throws IOException
*/
public void initServer() throws IOException{
channel=ServerSocketChannel.open();
channel.socket().bind(new InetSocketAddress(port));
//设置服务socket为非阻塞方式
channel.configureBlocking(false);
//注册channel到selector
channel.register(selector, SelectionKey.OP_ACCEPT);
}
/**
*
* 监听Selector对channel的选择
* 循环监听
*/
public void listen(){
System.out.println("监听-----9999");
for(;;){
try {
//执行select操作对channel通道的选择
//每次选出就绪(及有数据读取、写出)的通道
//但返回的对象为SelectionKeys
selector.select();
Iterator<SelectionKey> keys=selector.selectedKeys().iterator();
while(keys.hasNext()) {
SelectionKey key=keys.next();
if(key.isAcceptable()){
//可以选择的channel
channel=(ServerSocketChannel) key.channel();
//接到客户端的socket
SocketChannel client=channel.accept();
//设置客户端socket通道为非阻塞方式
client.configureBlocking(false);
//客户端socket设置为对读取数据感兴趣
client.register(selector, SelectionKey.OP_READ);
}else if(key.isReadable()){
SocketChannel client=(SocketChannel) key.channel();
//读取数据到buffer中
if(client.read(buffer)>0){
//反转数据,及把buffer的指针指回0,从头开始读取数据
buffer.flip();
CharBuffer charBuffer=decoder.decode(buffer);
System.out.println("读取到的数据:"+charBuffer.toString());
//将clientsocket注册为写事件
client.register(selector, SelectionKey.OP_WRITE);
//将获取的附加在SelectionKey中,以便下次使用,每一次将覆盖下一次。
key.attach(charBuffer.toString());
}else{
//没有数据则关闭通道
client.close();
}
buffer.clear();
}else if(key.isWritable()){
SocketChannel client=(SocketChannel) key.channel();
//想客户端写数据
client.write(encoder.encode(CharBuffer.wrap("欢迎访问服务器"+key.attachment())));
client.close();
}
}
//为了在下一次select操作中,更新selectionKey 必须的操作
keys.remove();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
NioServer server=new NioServer();
try {
server.initSelector();
server.initServer();
server.listen();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.Iterator;
/**
*
*Nio客户端,一个线程同时发起多个通道
*/
public class NioClient {
String host="127.0.0.1";
int port=9999;
CharsetEncoder encoder=Charset.forName("GB2312").newEncoder();
CharsetDecoder decoder=Charset.forName("GB2312").newDecoder();
SocketChannel channel;
Selector selector;
ByteBuffer buffer=ByteBuffer.allocate(1024);
public void initSelector() throws IOException{
selector=Selector.open();
}
public void initClient() throws IOException{
channel=SocketChannel.open();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_CONNECT);
channel.connect(new InetSocketAddress(host,port));
}
public void process() throws IOException{
for(;;){
selector.select();
Iterator<SelectionKey> keys=selector.selectedKeys().iterator();
while (keys.hasNext()) {
SelectionKey key=keys.next();
if(key.isConnectable()){
SocketChannel sc=(SocketChannel) key.channel();
if(sc.isConnectionPending()){
sc.finishConnect();
}
sc.write(encoder.encode(CharBuffer.wrap("你好! 服务器!")));
sc.register(selector, SelectionKey.OP_READ);
}else if(key.isReadable()){
SocketChannel sc=(SocketChannel) key.channel();
if(sc.read(buffer)>0){
buffer.flip();
System.out.println(decoder.decode(buffer).toString());
buffer.clear();
}else {
sc.close();
}
}
}
}
}
public static void main(String[] args) {
NioClient client=new NioClient();
try {
client.initSelector();
client.initClient();
client.process();
} catch (IOException e) {
e.printStackTrace();
}
}
}
NIO有众多的实现:mina 、tomcat、jttey等。
上一篇: Java NIO
推荐阅读
-
JDK1.9怎么安装配置?Java SE 9(JDK9)详细安装教程+环境变量配置方法
-
java中hashCode和equals什么关系,hashCode到底怎么用的
-
java中finally块儿是怎么工作的?有什么意义?
-
java中哪块代码或说什么代码应该放在try块中呢?
-
java中为什么接口中的属性和方法都默认为public?
-
java多线程关键字volatile、lock、synchronized
-
spring boot从redis取缓存发生java.lang.ClassCastException异常
-
java中如果我老是少捕获什么异常,如何处理?
-
java中如何能知道应该捕获什么样的异常?举例
-
java中如何用urlrewritefilter实现网站伪静态?