Nio也就是继JDK1.4之后关于io的新特性的new Io,也就是传说中的无阻塞io。
Nio主要包括几个方面:
ByteBuffer:Channel:Selector:
原理部分下次再整理,本次主要是进行实例。
下面要实现就是使用nio进行简单的文本传递。
服务端:
public class MainServer {
private static final int port = 19999;
private static ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
ServerSocketChannel server = ServerSocketChannel.open();
Selector sel = Selector.open();
server.socket().bind(new InetSocketAddress(port));
//无阻塞
server.configureBlocking(false);
//绑定连接事件。
server.register(sel, SelectionKey.OP_ACCEPT);
System.out.println("server start");
while (true) {
sel.select();
Iterator iter = sel.selectedKeys().iterator();
while (iter.hasNext()) {
SelectionKey key = (SelectionKey) iter.next();
iter.remove();
// 判断是否有新的连接到达
if (key.isAcceptable()) {
System.out.println("有新连接");
SocketChannel sc = server.accept();
sc.configureBlocking(false);
sc.register(sel, SelectionKey.OP_READ);
}
//判断是否可读取
if (key.isReadable()) {
SocketChannel sc = (SocketChannel) key.channel();
sc.configureBlocking(false);
int count = sc.read(buffer);
if (count <= 0) {
System.out.println("客户端已经关闭了");
sc.close();
} else {
System.out.println("有数据过来了");
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
String msg = new String(bytes);
System.out.println("收到信息>>" + msg);
buffer.clear();
}
}
}
}
}
}
客户端:
public class MainClient {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
SocketChannel client = SocketChannel.open();
client.configureBlocking(false);
Selector selector = Selector.open();
client.register(selector, SelectionKey.OP_CONNECT);
client.connect(new InetSocketAddress("localhost", 19999));
String message = "client test";
ByteBuffer bb = ByteBuffer.allocate(message.length());
boolean flag = true;
while (flag) {
selector.select();
Iterator it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = (SelectionKey) it.next();
it.remove();
if (key.isConnectable()) {
System.out.println("客户端连接上");
SocketChannel sc = (SocketChannel) key.channel();
if (sc.isConnectionPending())
sc.finishConnect();
sc.register(selector, SelectionKey.OP_WRITE);
}
if (key.isWritable()) {
System.out.println("客户端可以写");
SocketChannel sc = (SocketChannel) key.channel();
bb.clear();
bb.put(message.getBytes());
bb.flip();
sc.write(bb);
//发完一条信息,退出发送,关闭连接。
flag = false;
}
}
}
//关闭连接
client.close();
}
}
心得:
使用NIO进行传输的时候,也跟普通scoket差不多。其中使用ServerSocketChannel来作为服务端的channel,使用SocketChannel作为客户端的channel。其中channel可以理解为连接的通道。
sel.select();
Iterator iter = sel.selectedKeys().iterator();
chanel的selectedKeys可以理解为一次连接的实例了。每一个key可以调用其channel方法生成一个ScoketChannel。然后通过这个ScoketChannel来获取传输的内容,或者输入内容。
PS:
在服务端获取客户端传输过来的字符串时,使用ByteBuffer获得的方法是:
buffer.flip();
byte[] bytes=new byte[buffer.remaining()];
buffer.get(bytes);
String msg = new String(bytes);
通过该方法可以将客户端传送的字符byte组装为String。
在客户端传输的为一个固定的String,也可以将这个demo改写,改成控制台输入,作成一个简单的聊天程序。
另外,注意
buffer.flip() 的运用。