我正在阅读以下教程: http://tutorials.jenkov.com/java-nio/selectors.html
我觉得我不理解以下文章的很多细节,但我试图在文章末尾调用示例。
我的最终代码看起来如此:
public static void main(String[] args) throws IOException {
ServerSocketChannel channel = ServerSocketChannel.open();
Selector selector = Selector.open();
channel.configureBlocking(false);
SelectionKey selectionKey = channel.register(selector, SelectionKey.OP_READ);
while (true) {
int readyChannels = selector.select();
if (readyChannels == 0) continue;
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();//cause of exception
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
// a connection was accepted by a ServerSocketChannel.
} else if (key.isConnectable()) {
// a connection was established with a remote server.
} else if (key.isReadable()) {
// a channel is ready for reading
} else if (key.isWritable()) {
// a channel is ready for writing
}
keyIterator.remove();
}
}
}
作为这种方法调用的结果,我看到了以下堆栈跟踪:
Exception in thread "main" java.lang.IllegalArgumentException
at java.nio.channels.spi.AbstractSelectableChannel.register(AbstractSelectableChannel.java:196)
at java.nio.channels.SelectableChannel.register(SelectableChannel.java:277)
...
我的完整代码变体:
public class NioSelectorTest {
public static void main(String[] args) {
new Thread(new Receiver()).start();
new Thread(new Sender()).start();
}
}
class Receiver implements Runnable {
private static byte[] data = new byte[255];
public void run() {
try {
for (int i = 0; i < data.length; i++)
data[i] = (byte) i;
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
server.socket().bind(new InetSocketAddress(9000));
Selector selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();
Set readyKeys = selector.selectedKeys();
Iterator iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
if (key.isAcceptable()) {
SocketChannel client = server.accept();
System.out.println("Accepted connection from " + client);
client.configureBlocking(false);
ByteBuffer source = ByteBuffer.wrap(data);
SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE);
key2.attach(source);
} else if (key.isWritable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer output = (ByteBuffer) key.attachment();
if (!output.hasRemaining()) {
output.rewind();
}
client.write(output);
}
key.channel().close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Sender implements Runnable {
public void run() {
try {
SocketChannel sChannel = SocketChannel.open();
sChannel.configureBlocking(false);
sChannel.connect(new InetSocketAddress("localhost", 9000));
while (!sChannel.finishConnect()) {
ByteBuffer buf = ByteBuffer.allocateDirect(1024);
buf.put((byte) 0xFF);
buf.flip();
int numBytesWritten = sChannel.write(buf);
System.out.println("sent " + numBytesWritten + " bytes");
}
} catch (IOException exception) {
exception.printStackTrace();
}
}
}
在控制台中我看到了
来自java.nio.channels.SocketChannel的已接受连接[已连接 local = / 127.0.0.1:9000 remote = / 127.0.0.1:50940]
在调试中我看到我无法进入这个循环:
while (!sChannel.finishConnect()) {
...
答案 0 :(得分:0)
SelectionKey selectionKey = channel.register(selector, SelectionKey.OP_READ);
对于ServerSocketChannel,这应该是OP_ACCEPT。
答案 1 :(得分:-1)
在Java文档中,编写了register方法抛出
IllegalArgumentException - 如果ops中的某个位与此通道支持的操作不对应,即,如果设置&amp; ~validOps()!= 0
(资料来源:http://bit.ly/1lSBdX8)
我认为你需要首先绑定一个特定的端口,并在该SocketChannel上注册选择器。因此,代码的开头应如下所示:
ServerSocketChannel channel = ServerSocketChannel.open();
channel.socket().bind(new InetSocketAddress(8080)); // 8080 is the port you'll be listening
SocketChannel socketChannel = serverSocketChannel.accept();
Selector selector = Selector.open();
socketChannel.configureBlocking(false);
SelectionKey selectionKey = socketChannel.register(selector, SelectionKey.OP_READ);
...