I found some sample code of java nio:
ServerSocketChannel server = ServerSocketChannel.open();
Selector selector = Selector.open();
server.socket().bi
Because until you do it you can't detect new event repetitions.
if you dont invoke remove method you will find it also work fine。
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
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.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@SuppressWarnings({ "unchecked" })
public class NioServer {
ServerSocketChannel serverChannel;
ServerSocket serverSocket;
public final int port;
private Selector selector;
ByteBuffer buffer = ByteBuffer.allocate(1024);
NioServer(final int port) {
this.port = port;
}
void init() throws Exception {
// 创建 ServerSocketChannel、ServerSocket
serverChannel = ServerSocketChannel.open();
serverSocket = serverChannel.socket();
serverSocket.bind(new InetSocketAddress(port));
// 设置通道为非阻塞模式
serverChannel.configureBlocking(false);
// 开启通道选择器,并注册 ServerSocketChannel
selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
}
void go() throws Exception {
while (true) {
int num = selector.select();
if (num <= 0)
continue;
Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
System.out.println(selector.selectedKeys().size()); //等于线程数量
while (keyIter.hasNext()) {
final SelectionKey key = keyIter.next();
System.out.println("所有的key"+key);
// 接收一个Socket连接
// key.isAcceptable()如果为true,说明channnel支持accept(),也就是说明是一个ServerSocketChannel
if (key.isAcceptable()) {
System.out.println("可以连接的key:"+key);
SocketChannel clientChannel = serverChannel.accept();
if (clientChannel != null) {
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
}
}
// 如果isReadable()为true,说明是一个SocketChannel
if (key.isReadable()) {
String requestContent = read(key);
// 业务处理
// responseContent=doSomthing(requestContent);
write(key, "ok" /* responseContent */);
}
// keyIter.remove();
}
}
}
// 从通道读取数据
String read(SelectionKey key) throws Exception {
SocketChannel socketChannel = (SocketChannel) key.channel();
buffer.clear();// 这一步必须有
int len = 0;
StringBuffer str = new StringBuffer();
while ((len = socketChannel.read(buffer)) > 0) {
byte[] bs = buffer.array();
String block = new String(bs, 0, len);
System.out.println("Server read: " + block);
str.append(block);
}
buffer.clear();
return str.toString();
}
// 写数据到通道
void write(SelectionKey key, String str) throws Exception {
SocketChannel socketChannel = (SocketChannel) key.channel();
buffer.clear();
buffer.put(str.getBytes());
buffer.flip();// 这一步必须有
socketChannel.write(buffer);
}
public static void main(String[] args) throws Exception {
final int port = 10000;
NioServer server = new NioServer(port);
server.init();
/// ========================================================
// 接下来模拟3个Client并发访问服务器
int poolsize = 1;
ExecutorService pool = Executors.newFixedThreadPool(poolsize);
Collection<Callable> tasks = new ArrayList<Callable>(10);
final String clientname = "clientThread";
for (int i = 0; i < poolsize; i++) {
final int n = i;
// 若每一个Client都保持使用BIO方式发送数据到Server,并读取数据。
tasks.add(new Callable() {
@Override
public Object call() throws Exception {
Socket socket = new Socket("127.0.0.1", port);
final InputStream input = socket.getInputStream();
final OutputStream out = socket.getOutputStream();
final String clientname_n = clientname + "_" + n;
// BIO读取数据线程
new Thread(clientname_n + "_read") {
@Override
public void run() {
byte[] bs = new byte[1024];
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int len = 0;
try {
while ((len = input.read(bs)) != -1) {
System.out.println("Clinet thread " + Thread.currentThread().getName()
+ " read: " + new String(bs, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
// BIO写数据线程
new Thread(clientname_n + "_write") {
@Override
public void run() {
int a = 0;
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
String str = Thread.currentThread().getName() + " hello, " + a;
try {
out.write(str.getBytes());
a++;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
return null;
}
});
}
pool.invokeAll((Collection<? extends Callable<Object>>) tasks);
server.go();
}
}
just print it and test it 。you will find even you not remove,use key.isAcceptable() can filter corrent result
Because the Selector never does that, it only adds to the set, so if you don't do it you will reprocess the event yourself next time the Selector returns.
avoid publicSelectedKeys
private final Set<SelectionKey> publicSelectedKeys;
Because removing key from selected set, as it's been Handled, it will wait for next selection event.
selected set contains keys of the ready channels.
selector.select(); //This may block for a long time. Upon returning, the elected set contains keys of the ready channels.
Get an iterator over the set of selected keys and Perform the Business Information
Iterator it = selector.selectedKeys().iterator( );
Finally Remove key from selected set; it's been handled
it.remove( );
Keys can be directly removed from this set, but not added. Attempting to add to the selected key set throws java.lang.UnsupportedOperationException.