java NIO

自从 J2SE 1.4 版本以来, JDK 发布了全新的 I/O 类库,简称 NIO ,其不但引入了全新的高效的 I/O 机制,同时,也引入了多路复用的异步模式。 NIO 的包中主要包含了这样几种抽象数据类型:

  Buffer :包含数据且用于读写的线形表结构。其中还提供了一个特殊类用于内存映射文件的 I/O 操作。

  Charset :它提供 Unicode 字符串影射到字节序列以及逆映射的操作。

  Channels :包含 socket file pipe 三种管道,都是全双工的通道。

  Selector :多个异步 I/O 操作集中到一个或多个线程中(可以被看成是 Unix select() 函数的面向对象版本)。

 

看看IO与NIO的结构对比:


java NIO

 

以下是一个简单实例:

package com;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
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.util.Iterator;

public class NIOServer {
	// 定义缓存大小
	private int BLOCK = 4096;
	// 定义监视器
	private Selector selector;
	private String filename = "E:\\Hibernate3.xml";
	// 定义客户端缓存
	private ByteBuffer clientBuffer = ByteBuffer.allocate(BLOCK);
	// 定义编码器
	private CharsetDecoder decoder;

	public NIOServer(int port) throws IOException {
		this.selector = this.getSelector(port);
		Charset charset = Charset.forName("GB2312");
		this.decoder = charset.newDecoder();
	}

	// 获取Selector
	protected Selector getSelector(int port) throws IOException {
		ServerSocketChannel server = ServerSocketChannel.open();
		Selector sel = Selector.open();
		// 将服务端套接字通道绑定到指定端口上
		server.socket().bind(new InetSocketAddress(port));
		server.configureBlocking(false);
		// 将服务端套接字通道注册到监视器上,监视客户端的请求操作.
		server.register(sel, SelectionKey.OP_ACCEPT);
		return sel;
	}

	// 处理与客户端的交互
	public class HandleClient {
		protected FileChannel channel;
		protected ByteBuffer buffer;

		public HandleClient() throws IOException {
			this.channel = new FileInputStream(filename).getChannel();
			this.buffer = ByteBuffer.allocate(BLOCK);
		}

		public ByteBuffer readBlock() {
			try {
				buffer.clear();
				int count = channel.read(buffer);
				buffer.flip();
				if (count <= 0)
					return null;
			} catch (IOException e) {
				e.printStackTrace();
			}
			return buffer;
		}

		public void close() {
			try {
				channel.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	// 监听端口
	public void listen() {
		try {
			for (;;) {
				selector.select();
				// 得到所有监视对象的KEY,查看通道的操作状态
				Iterator<SelectionKey> iter = selector.selectedKeys()
						.iterator();
				while (iter.hasNext()) {
					SelectionKey key = iter.next();
					iter.remove();
					handleKey(key);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// 处理事件
	protected void handleKey(SelectionKey key) throws IOException {
		if (key.isAcceptable()) { // 接收请求
			ServerSocketChannel server = (ServerSocketChannel) key.channel();
			// 当调用accept()时,IO阻塞直到建立连接并返回SocketChannel.
			SocketChannel channel = server.accept();
			// 设定非阻塞式IO处理方式.
			channel.configureBlocking(false);
			// 将通道注册到Selector,并由Selector监视通道的状态.
			channel.register(selector, SelectionKey.OP_READ);
		} else if (key.isReadable()) { // 读信息
			SocketChannel channel = (SocketChannel) key.channel();
			int count = channel.read(clientBuffer);
			if (count > 0) {
				clientBuffer.flip();
				CharBuffer charBuffer = decoder.decode(clientBuffer);
				System.out.println("Client >>" + charBuffer.toString());
				SelectionKey wKey = channel.register(selector,
						SelectionKey.OP_WRITE);
				wKey.attach(new HandleClient());
			} else
				channel.close();
			clientBuffer.clear();
		} else if (key.isWritable()) { // 写事件
			SocketChannel channel = (SocketChannel) key.channel();
			HandleClient handle = (HandleClient) key.attachment();
			ByteBuffer block = handle.readBlock();
			if (block != null)
				channel.write(block);
			else {
				handle.close();
				channel.close();
			}
		}
	}

	public static void main(String[] args) {
		int port = 12345;
		try {
			NIOServer server = new NIOServer(port);
			System.out.println("Listernint on " + port);
			while (true) {
				server.listen();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

package com;

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.CharsetEncoder;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NIOClient {
	private static int SIZE = 10;
	private static InetSocketAddress ip = new InetSocketAddress("localhost",
			12345);
	private static CharsetEncoder encoder = Charset.forName("GB2312")
			.newEncoder();

	static class Download implements Runnable {
		protected int index;

		public Download(int index) {
			this.index = index;
		}

		public void run() {
			try {
				long start = System.currentTimeMillis();
				// 建立一个套接字通道
				SocketChannel client = SocketChannel.open();
				// 设定为非阻塞式
				client.configureBlocking(false);
				// 打开一个监视器
				Selector selector = Selector.open();
				// 注册连接请求事件到监视器上
				client.register(selector, SelectionKey.OP_CONNECT);
				// 让客户端连接服务端
				client.connect(ip);
				ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
				int total = 0;
				FOR: for (;;) {
					selector.select();
					// 得到所有监视对象的KEY,查看通道的操作状态
					Iterator<SelectionKey> iter = selector.selectedKeys()
							.iterator();
					while (iter.hasNext()) {
						SelectionKey key = iter.next();
						iter.remove();
						if (key.isConnectable()) {
							SocketChannel channel = (SocketChannel) key
									.channel();
							if (channel.isConnectionPending())
								channel.finishConnect();
							channel.write(encoder.encode(CharBuffer
									.wrap("Hello from " + index)));
							// 再次向监视器注册通道的读取状态的监视
							channel.register(selector, SelectionKey.OP_READ);
						} else if (key.isReadable()) {
							SocketChannel channel = (SocketChannel) key
									.channel();
							int count = channel.read(buffer);
							if (count > 0) {
								total += count;
								buffer.clear();
							} else {
								client.close();
								break FOR;
							}
						}
					}
				}
				double last = (System.currentTimeMillis() - start) * 1.0 / 1000;
				System.out.println("Thread " + index + " downloaded " + total
						+ "bytes in " + last + "s.");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) throws IOException {
		ExecutorService exec = Executors.newFixedThreadPool(SIZE);
		for (int index = 0; index < SIZE; index++) {
			exec.execute(new Download(index));
		}
		exec.shutdown();
	}
}

你可能感兴趣的:(J2SE,nio)