欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JAVA NIO

程序员文章站 2022-04-24 10:30:34
...

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等。