java NIO
Java NIO提供了与标准IO不同的IO工作方式:
- Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
- Asynchronous IO(异步IO):Java NIO可以让你异步的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。
- Selectors(选择器):Java NIO引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。
1. Channel的实现
Java NIO中最重要的通道的实现:
- FileChannel:从文件中读写数据。
- DatagramChannel:能通过UDP读写网络中的数据。
- SocketChannel:能通过TCP读写网络中的数据。
- ServerSocketChannel:可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。
2. Buffer的类型
Java NIO 有以下Buffer类型:
- ByteBuffer
- MappedByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
2. Selector(选择器)
Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。
Selector监听Channel时间类型:
- SelectionKey.OP_CONNECT connect事件 socketChannel 通过连接事件连接
- SelectionKey.OP_ACCEPT accept 事件 serverSocketChannel 通过accept方法接收SocketChannel
- SelectionKey.OP_READ Read 事件 Channel通过read方法将数据写到buffer中
- SelectionKey.OP_WRITE Write 事件 Channel通过write方法将buffer中的数据写到通道中
eg:
监听端口888得到的数据
ServerSocketChannel serverSocketChannel1 = ServerSocketChannel.open();
serverSocketChannel1.socket().bind(new InetSocketAddress(888)); // 监听888端口
SocketChannel channel = serverSocketChannel.accept();
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
Selector selector = Selector.open();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_ACCEPT); // socket接收
socketChannel.register(selector, SelectionKey.OP_READ); // 读
while(true) {
int readyChannels = selector.select();
if(readyChannels == 0) continue;
Set selectedKeys = selector.selectedKeys();
Iterator keyIterator = selectedKeys.iterator();
while(keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if(key.isAcceptable()) {
// a connection was accepted by a ServerSocketChannel.
ServerSocketChannel serverSocketChannel = SelectionKey.channel();
SocketChannel socketChannel = serverSocketChannel.accept();
ByteBuffer buf = ByteBuffer.allocate(48);
socketChannel.read(buf);
} else if (key.isConnectable()) {
// a connection was established with a remote server.
} else if (key.isReadable()) {
// a channel is ready for reading
} else if (key.isWritable()) {
SocketChannel socketChannel = SelectionKey.channel();
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip(); // 将Buffer从写模式切换到读模式
socketChannel.write(buf);
// a channel is ready for writing
}
keyIterator.remove();
}
}
参考:http://www.iteye.com/magazines/132-Java-NIO#590