java nio ServerSocketChannel accept 如何工作?
How java nio ServerSocketChannel accept works?
我不明白 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();
}
}
这里我有几个问题:
- selKey.channel() return 一个 ServerSocketChannel 是否与我们在开始时使用 ServerSocketChannel.open() 创建的通道完全相同?如果不是,那是什么?
- 更重要的问题:在大多数其他教程中selKey.channel();步骤被跳过,他们只使用 SocketChannel client = server.accept();例如这里: http://www.onjava.com/pub/a/onjava/2002/09/04/nio.html?page=2 and here: http://www.developer.com/java/article.php/10922_3837316_2/Non-Blocking-IO-Made-Possible-in-Java.htm 那么,server.accept() 如何知道我们处理的当前密钥?
在 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);
}
selKey.channel() return a ServerSocketChannel is it exactly the same channel we created in the beginning with ServerSocketChannel.open()?
是的。
More important question: in most other tutorials selKey.channel(); step is skipped and they simply use SocketChannel client = server.accept(); For example here: http://www.onjava.com/pub/a/onjava/2002/09/04/nio.html?page=2 and here: http://www.developer.com/java/article.php/10922_3837316_2/Non-Blocking-IO-Made-Possible-in-Java.htm So, how does server.accept() knows about current key we process?
没有。他们假设只有一个 ServerSocketChannel
。你的方法更好:它更通用。
In http://www.developer.com/java/article.php/10922_3837316_2/Non-Blocking-IO-Made-Possible-in-Java.htm they even suggest to accept channel in new thread.
我不知道为什么。这是一个非阻塞调用。它会立即return。这个建议毫无意义。忽略它。这是六年前质量很差的教程,但十三年前就有更好的教程了。试试 Oracle 教程。这个的作者好像一点都不明白非阻塞模式的意义。为每个事件使用单独的线程的建议是完全荒谬的。他也不明白如何使用OP_WRITE。他对 cancel()
做出了错误的断言。我可以继续。他是否执行过这段代码值得怀疑:他当然没有以任何方式调查它的行为。如何编写不可扩展的 NIO 服务器。了不起。
I guess it is possible that the following situation may occur.
我什至不明白为什么您会同时在两个线程中接受,更不用说它接受哪个线程对客户端有什么影响了。这是 none 存在的难度。
So, could you please explain how selector works in pair with ServerSocketChannel and accept method? Because I don't understand in which order #accept accepts clients and how this order related to selectedKeys.
accept()
方法 return 是积压队列中的下一个套接字,并且 OP_ACCEPT 只要积压队列非空就会触发。它非常简单,没有神秘感。该订单根本没有 'relate to selected keys'。所选键是 ServerSocketChannel
的键。
编辑:看来你有一个重大的误解。考虑:
- 您为
OP_ACCEPT
创建并注册了一个 ServerSocketChannel
。
- 两个客户端同时连接。
- 现在只有一个
SelectionKey
存在,因此在选定键集中只有一个:ServerSocketChannel
。
- 然后您在该密钥上处理您的
isAcceptable()
案例;接受一个或两个连接;为 OP_READ.
注册这些频道
- 现在存在三个选择键,并且 none 在选择键集中,因为您清除了它。
- 两个客户端都发送了一些数据。
- 现在您有两个选择键可以在选定键集中读取。
好吗?
Can I simply do the following:
当然可以,但是为什么呢?将简单的事情复杂化并没有什么好处。按照第一种方式做。
我不明白 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();
}
}
这里我有几个问题:
- selKey.channel() return 一个 ServerSocketChannel 是否与我们在开始时使用 ServerSocketChannel.open() 创建的通道完全相同?如果不是,那是什么?
- 更重要的问题:在大多数其他教程中selKey.channel();步骤被跳过,他们只使用 SocketChannel client = server.accept();例如这里: http://www.onjava.com/pub/a/onjava/2002/09/04/nio.html?page=2 and here: http://www.developer.com/java/article.php/10922_3837316_2/Non-Blocking-IO-Made-Possible-in-Java.htm 那么,server.accept() 如何知道我们处理的当前密钥?
在 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); }
selKey.channel() return a ServerSocketChannel is it exactly the same channel we created in the beginning with ServerSocketChannel.open()?
是的。
More important question: in most other tutorials selKey.channel(); step is skipped and they simply use SocketChannel client = server.accept(); For example here: http://www.onjava.com/pub/a/onjava/2002/09/04/nio.html?page=2 and here: http://www.developer.com/java/article.php/10922_3837316_2/Non-Blocking-IO-Made-Possible-in-Java.htm So, how does server.accept() knows about current key we process?
没有。他们假设只有一个 ServerSocketChannel
。你的方法更好:它更通用。
In http://www.developer.com/java/article.php/10922_3837316_2/Non-Blocking-IO-Made-Possible-in-Java.htm they even suggest to accept channel in new thread.
我不知道为什么。这是一个非阻塞调用。它会立即return。这个建议毫无意义。忽略它。这是六年前质量很差的教程,但十三年前就有更好的教程了。试试 Oracle 教程。这个的作者好像一点都不明白非阻塞模式的意义。为每个事件使用单独的线程的建议是完全荒谬的。他也不明白如何使用OP_WRITE。他对 cancel()
做出了错误的断言。我可以继续。他是否执行过这段代码值得怀疑:他当然没有以任何方式调查它的行为。如何编写不可扩展的 NIO 服务器。了不起。
I guess it is possible that the following situation may occur.
我什至不明白为什么您会同时在两个线程中接受,更不用说它接受哪个线程对客户端有什么影响了。这是 none 存在的难度。
So, could you please explain how selector works in pair with ServerSocketChannel and accept method? Because I don't understand in which order #accept accepts clients and how this order related to selectedKeys.
accept()
方法 return 是积压队列中的下一个套接字,并且 OP_ACCEPT 只要积压队列非空就会触发。它非常简单,没有神秘感。该订单根本没有 'relate to selected keys'。所选键是 ServerSocketChannel
的键。
编辑:看来你有一个重大的误解。考虑:
- 您为
OP_ACCEPT
创建并注册了一个ServerSocketChannel
。 - 两个客户端同时连接。
- 现在只有一个
SelectionKey
存在,因此在选定键集中只有一个:ServerSocketChannel
。 - 然后您在该密钥上处理您的
isAcceptable()
案例;接受一个或两个连接;为OP_READ.
注册这些频道
- 现在存在三个选择键,并且 none 在选择键集中,因为您清除了它。
- 两个客户端都发送了一些数据。
- 现在您有两个选择键可以在选定键集中读取。
好吗?
Can I simply do the following:
当然可以,但是为什么呢?将简单的事情复杂化并没有什么好处。按照第一种方式做。