服務端代碼:
坑: 因為寫事件在selector中會一直會true, 是以會一直向client寫東西,是以要在寫事件完成後,取消寫事件。
package com.nio.yubo;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
public class NioServer {
public NioServer(int port) {
this.port = port;
}
private int port;
private Selector selector;
private ServerSocketChannel serverCh;
private Selector getSelector() throws IOException
{
selector = Selector.open();
serverCh = ServerSocketChannel.open();
serverCh.configureBlocking(false);
ServerSocket socket = serverCh.socket();
InetSocketAddress address = new InetSocketAddress(port);
socket.bind(address);
serverCh.register(selector, SelectionKey.OP_ACCEPT);
return selector;
}
public void listen()
{
System.out.println("Start to listen on port:" + this.port);
while(true)
{
try {
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while(it.hasNext()) {
SelectionKey key = it.next();
it.remove();
process(key);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void process(SelectionKey key) {
if(key.isAcceptable())
{
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel channel = null;
try {
channel = server.accept();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
channel.configureBlocking(false);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
channel.register(selector, SelectionKey.OP_READ);
} catch (ClosedChannelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else if(key.isReadable()) {
//fix me
SocketChannel channel = (SocketChannel)key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
try {
int len = channel.read(buffer);
if(len > 0) {
buffer.flip();
System.out.println("Content len is:" + len + "pos is: " + buffer.position() + "limit:" + buffer.limit() + "ca:" +buffer.capacity());
String content = new String(buffer.array());
System.out.println("Content in readable is:" + content);
SelectionKey skey = channel.register(selector, SelectionKey.OP_WRITE);
skey.attach(content); // 為一下次寫事件的key 準備資料
}
else
{
channel.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
buffer.clear();
}
else if (key.isWritable()) {
SocketChannel channel = (SocketChannel)key.channel();
String content = (String)key.attachment();
ByteBuffer block = ByteBuffer.wrap( ("hello:" + content ).getBytes());
try {
channel.write(block);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
key.cancel(); // 這裡是取消寫事件
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
NioServer myServer = new NioServer(9999);
try {
myServer.getSelector();
myServer.listen();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
用戶端代碼:
坑:
在把内容寫到buffer 後,在發送到channel 前,要把buffer flip() 一下,不然position, limit的值會不對,發到server的東西是空的。
package com.nio.yubo;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
public class NioClient {
Selector selector = null;
SocketChannel channel = null;
public void connect()
{
try {
channel = (SocketChannel)SocketChannel.open();
channel.connect(new InetSocketAddress( "127.0.0.1", 9999));
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("my name is tom".getBytes());
buffer.flip(); // 這裡一定要記得恢複positon到0
if(buffer.hasRemaining())
{
System.out.println("Client send: " + new String(buffer.array()));
channel.write(buffer);
}
buffer.clear();
channel.read(buffer);
buffer.flip();
if(buffer.hasRemaining())
{
System.out.println(new String(buffer.array()));
}
buffer.clear();
channel.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new NioClient().connect();
}
}