服务端代码:
坑: 因为写事件在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();
}
}