您的位置:首页 > 编程语言 > Java开发

Java NIO基本使用介绍

2013-07-28 23:47 363 查看
NIO主要包括Channel,Buffer,Selector三个核心元素组成。

Channel即通道,l和Buffer有好几种类型。下面是JAVA NIO中的一些主要Channel的实现:

FileChannel

DatagramChannel

SocketChannel

ServerSocketChannel

正如你所看到的,这些通道涵盖了UDP 和 TCP 网络IO,以及文件IO。

Buffer有IntBuffer,CharBuffer,FloatBuffer。。。。。

可以在Selector上注册通道。

Selector所在线程负责处理监听,待所关注的事件到达时,将事件分发给在Selector上注册的channel作异步处理,如下图所示。



Buffer的基本用法

使用Buffer读写数据一般遵循以下四个步骤:

调用channel的read()方法,将channel中的数据写入到Buffer中。

调用
flip()
方法
flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。

换句话说,position现在用于标记读的位置,limit表示之前写进了多少个byte、char等 —— 现在能读取多少个byte、char等。

public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}


调用channel的write()方法,将Buffer中的数据写入channel中。

调用
clear()
方法或者
compact()
方法

为了理解Buffer的工作原理,需要熟悉它的三个属性:

capacity

position

limit

position和limit的含义取决于Buffer处在读模式还是写模式。不管Buffer处在什么模式,capacity的含义总是一样的。

这里有一个关于capacity,position和limit在读写模式中的说明,详细的解释在插图后面。



capacity

作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。

position

当你写数据到Buffer中时,position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.

当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。

limit

在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。

当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到之前写入的所有数据(limit被设置成已写数据的数量,这个值在写模式下就是position)

使用JAVA NIO编写一个客户端与服务端通信的例子。

Server

package com.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class Server {
private Selector selector;
private ByteBuffer readBuffer = ByteBuffer.allocate(100);

public void start() throws IOException {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ssc.socket().bind(new InetSocketAddress("localhost", 8002));
selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
while (!Thread.currentThread().isInterrupted()) {
selector.select();
Set selectedKeys = selector.selectedKeys();
Iterator iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
if (!key.isValid()) {
continue;
}
if (key.isAcceptable()) {
accept(key);
} else if (key.isReadable()) {
read(key);
}
}
iterator.remove();
}
}

private void read(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
this.readBuffer.clear();
int readNum = 0;
try {
readNum = socketChannel.read(this.readBuffer);
} catch (IOException e) {
key.cancel();
socketChannel.close();
return;
}
if (readNum > 0) {
byte[] newBytes = new byte[readNum];
System.arraycopy(readBuffer.array(), 0, newBytes, 0, readNum);
String message = new String(newBytes);
System.out.println(message);
message = "你好,已收到你发的消息:" + message;
readBuffer.flip();
readBuffer = ByteBuffer.wrap(message.getBytes());
socketChannel.write(readBuffer);
}
}

private void accept(SelectionKey key) throws IOException {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel clientChanel = ssc.accept();
clientChanel.configureBlocking(false);
clientChanel.register(selector, SelectionKey.OP_READ);
System.out.println("a new client connected...");
}

public static void main(String[] args) throws IOException {
new Server().start();
}
}


Client

package com.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

public class Client {
private void start() throws IOException {
SocketChannel sc = SocketChannel.open();
sc.configureBlocking(false);
sc.connect(new InetSocketAddress("localhost", 8002));
Selector selector = Selector.open();
sc.register(selector, SelectionKey.OP_CONNECT );
Scanner scanner = new Scanner(System.in);
while (true) {
selector.select();
Set selectedKeys = selector.selectedKeys();
Iterator iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
if (key.isConnectable()) {
sc.finishConnect();
sc.register(selector, SelectionKey.OP_WRITE);
System.out.println("server connected");
break;
} else if (key.isWritable()) {
System.out.println("please input message");
String message = scanner.nextLine();
ByteBuffer writebufBuffer = ByteBuffer.wrap(message.getBytes());
sc.write(writebufBuffer);
sc.register(selector, SelectionKey.OP_READ);
}else if(key.isReadable()){
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int readNum = sc.read(readBuffer);
byte[] newBytes = new byte[readNum];
System.arraycopy(readBuffer.array(), 0, newBytes, 0, readNum);
String message = new String(newBytes);
System.out.println(message);
sc.register(selector, SelectionKey.OP_WRITE);
}
}
iterator.remove();
}
}

public static void main(String[] args) throws IOException {
new Client().start();
}
}


Client端输入abc后,Server端会将收到的信息返回到Client端,打印"你好,已收到......"



Server端也会打印出Client端发送的消息。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: