我无法了解NIO的工作原理。以下是示例代码:
// Create the server socket channel
ServerSocketChannel server = ServerSocketChannel.open();
// nonblocking I/O
server.configureBlocking(false);
// host-port 8000
server.socket().bind(new java.net.InetSocketAddress(host,8000));
// Create the selector
Selector selector = Selector.open();
// Recording server to selector (type OP_ACCEPT)
server.register(selector,SelectionKey.OP_ACCEPT);
while (true) {
selector.select(); // blocking operation
Iterator it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey selKey = (SelectionKey) it.next();
// THE MOST INTRIGUING PART HERE!!!
if (selKey.isAcceptable()) {
ServerSocketChannel ssChannel = (ServerSocketChannel) selKey.channel();
SocketChannel sc = ssChannel.accept();
}
it.remove();
}
}
我在这里有几个问题:
在http://www.developer.com/java/article.php/10922_3837316_2/Non-Blocking-IO-Made-Possible-in-Java.htm中,他们甚至建议在新帖子中接受频道。我想可能会出现以下情况。
key1 someClient1 acceptable
key2 someClient2 not acceptable
key3 someClient3 acceptable
startThread1
startThread3
scheduler decides to give time to thread3 instead of thread1
thread3 -> socket.accept() <- actually accepts client1
thread1 -> socket.accept() <- actually accepts client3
那么,您能否解释一下选择器如何与ServerSocketChannel和accept方法配对?因为我不明白#accept接受客户的顺序以及此订单与selectedKeys的关系。
我可以简单地执行以下操作:
int availableClients = 0;
while (it.hasNext()) {
SelectionKey selKey = (SelectionKey) it.next();
if (selKey.isAcceptable()) {
++availableClients;
}
it.remove();
}
for (int i = 0; i < availableClients; ++i) {
SocketChannel sc = server.accept();
doSomething(sc);
}
答案 0 :(得分:6)
selKey.channel()返回一个ServerSocketChannel它与我们在ServerSocketChannel.open()开头创建的通道完全相同吗?
是
更重要的问题:在大多数其他教程中selKey.channel();跳过步骤,他们只使用SocketChannel client = server.accept();例如:http://www.onjava.com/pub/a/onjava/2002/09/04/nio.html?page=2和此处:http://www.developer.com/java/article.php/10922_3837316_2/Non-Blocking-IO-Made-Possible-in-Java.htm那么,server.accept()如何知道我们处理的当前密钥?
没有。他们假设只有一个ServerSocketChannel
。你的方式更好:它更通用。
在http://www.developer.com/java/article.php/10922_3837316_2/Non-Blocking-IO-Made-Possible-in-Java.htm中,他们甚至建议在新帖子中接受频道。
我不知道为什么。这是一个非阻塞的电话。它会立即返回。这个建议毫无意义。忽略它。这是六年前质量很差的教程,但十三年前还有更好的教程。试试Oracle教程。这个人的作者似乎根本不理解非阻塞模式。为每个事件使用单独的线程的建议是完全和完全荒谬的。他也不明白如何使用OP_WRITE。他对cancel()
做出了错误的断言。我可以继续他曾经执行过这段代码是值得怀疑的:他当然没有以任何方式调查其行为。如何编写不可伸缩的NIO服务器。相当壮举。
我想可能会出现以下情况。
我甚至没有看到为什么你会同时接受两个线程,更不用说它们接受哪个客户端线程可能有什么关系。这是一个难以发明的难点。
那么,您能否解释一下选择器如何与ServerSocketChannel和accept方法配对?因为我不明白#accept接受客户端的顺序以及此命令与selectedKeys的关系。
accept()
方法返回积压队列中的下一个套接字,只要积压队列非空,就会触发OP_ACCEPT。它非常简单,没有神秘感。该订单根本不与“所选密钥相关”。所选键是ServerSocketChannel
的键。
ServerSocketChannel
创建并注册OP_ACCEPT
。SelectionKey
存在,因此在所选键集中只有一个:ServerSocketChannel
。isAcceptable()
个案;接受一个或两个连接;为OP_READ.
OK?
我可以简单地执行以下操作:
当然可以,但为什么呢?通过简单的东西制造复杂的东西是没有好处的。这是第一种方式。