我编写了一个使用选择器的java NIO服务器来接受来自客户端的连接。
我以为selector.select()会阻塞并返回多个键。我刚刚为OP_ACCEPT注册了选择器,它总是一次返回1个键
我做错了吗?
package com.bay.srikanth.client;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
public class FloodServer {
private final static Logger LOGGER = Logger.getLogger(FloodServer.class.getName());
private static int PORT = 5555;
private static ConcurrentHashMap<Integer, SocketChannel> chm
= new ConcurrentHashMap<Integer, SocketChannel>();
private static int msg = 0;
public static void main(String args[]) throws Exception {
// Create a new selector
Selector selector = Selector.open();
// Open a listener on each port, and register each one
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ServerSocket ss = ssc.socket();
InetSocketAddress address = new InetSocketAddress(PORT);
ss.bind(address);
//registers ACCEPT
ssc.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Going to listen on " + PORT);
while (true) {
LOGGER.log(Level.INFO, "Total active connections : " + chm.size());
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
LOGGER.log(Level.INFO, "Selected Keys on : " + selectedKeys + " with keys count : " + selectedKeys.size());
Iterator<SelectionKey> it = selectedKeys.iterator();
while (it.hasNext()) {
SelectionKey key = (SelectionKey) it.next();
if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
// Accept the new connection
ServerSocketChannel sscNew = (ServerSocketChannel) key.channel();
SocketChannel sc = sscNew.accept();
sc.configureBlocking(false);
// Add the new connection to the selector
//sc.register(selector, SelectionKey.OP_READ);
// Add the socket channel to the list
chm.put(sc.hashCode(), sc);
it.remove();
}
}
}
}
}
Flood Test客户端工具
package com.bay.srikanth.client;
import java.net.InetSocketAddress;
import java.nio.channels.SocketChannel;
import java.util.List;
import java.util.Vector;
public class FloodTest implements Runnable {
private static List<SocketChannel> channelSet = new Vector<SocketChannel>();
@Override
public void run() {
try {
for(int i=0; i<50; i++) {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(true);
//socketChannel.connect(new InetSocketAddress("10.9.242.70", 5555));
socketChannel.connect(new InetSocketAddress("localhost", 5555));
channelSet.add(socketChannel);
}
} catch(Exception ex) {
System.out.println(ex);
}
System.out.println(channelSet.size());
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String args[]) throws InterruptedException {
for(int i=0; i<100; i++) {
new Thread(new FloodTest()).start();
}
}
}
Apr 17, 2014 11:35:49 AM com.bay.srikanth.client.FloodServer main
INFO: Selected Keys on : [sun.nio.ch.SelectionKeyImpl@5e176f] with keys count : 1
Apr 17, 2014 11:35:49 AM com.bay.srikanth.client.FloodServer main
INFO: Total active connections : 2328
Apr 17, 2014 11:35:49 AM com.bay.srikanth.client.FloodServer main
INFO: Selected Keys on : [sun.nio.ch.SelectionKeyImpl@5e176f] with keys count : 1
Apr 17, 2014 11:35:49 AM com.bay.srikanth.client.FloodServer main
INFO: Total active connections : 2329
Apr 17, 2014 11:35:49 AM com.bay.srikanth.client.FloodServer main
INFO: Selected Keys on : [sun.nio.ch.SelectionKeyImpl@5e176f] with keys count : 1
Apr 17, 2014 11:35:49 AM com.bay.srikanth.client.FloodServer main
INFO: Total active connections : 2330
Apr 17, 2014 11:35:49 AM com.bay.srikanth.client.FloodServer main
INFO: Selected Keys on : [sun.nio.ch.SelectionKeyImpl@5e176f] with keys count : 1
始终,选择键上:[sun.nio.ch.SelectionKeyImpl@5e176f],键数:1,键数始终为1.我尝试增加线程,仍然是1。
有人可以回答这里的错误吗?
谢谢, SRIKANTH
答案 0 :(得分:1)
服务器套接字一次只能接受一个。
当你选择了多个套接字时,如果你接受一个客户端,如果你为OP_READ事件注册该套接字,那么当接受和读取事件发生在两个套接字上时,你可能会得到两个密钥。
只有在执行语句之前发生事件时,才会选择两个或更多键 selector.select();
当你在select中阻塞时,它将在单个事件之后出现,它不会阻止多个事件发生。 select()阻塞,直到至少有一个通道为您注册的事件做好准备。
在您的情况下,您只注册了一个服务器套接字。所以你只能获得一把钥匙。 我想这回答了你的问题。
答案 1 :(得分:0)
//sc.register(selector, SelectionKey.OP_READ);
这是您需要的线路。它被注释掉了。为什么呢?
注意,当你得到它时,你还需要一些代码来处理OP_READ,你需要创建它,remove()无条件和故障安全。最好的方法是在调用it.next()后直接移动它。
答案 2 :(得分:0)
我认为主要关键是你的客户只是一个线程。 虽然你有代码:
for(int i=0; i<50; i++) {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(true);
//socketChannel.connect(new InetSocketAddress("10.9.242.70", 5555));
socketChannel.connect(new InetSocketAddress("localhost", 5555));
channelSet.add(socketChannel);
}
50的请求逐个发送到服务器,因此您的服务器将逐个接受。
总结:服务器套接字一次只能接受一个