java nio ServerSocketChannel如何接受?

Vad*_*huk 3 java sockets network-programming nio nonblocking

我无法理解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();
     }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我有几个问题:

  1. selKey.channel()返回一个ServerSocketChannel它与我们在使用ServerSocketChannel.open()开始创建时完全相同吗?如果没有,那么它是什么?
  2. 更重要的问题:在大多数其他教程中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()如何知道我们处理的当前密钥?
  3. 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
    
    Run Code Online (Sandbox Code Playgroud)

那么,您能否解释一下选择器如何与ServerSocketChannel和accept方法配对?因为我不明白#accept接受客户端的顺序以及此命令如何与selectedKeys相关.

  1. 我可以简单地执行以下操作:

    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);
    }
    
    Run Code Online (Sandbox Code Playgroud)

use*_*421 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.

编辑:看来你有一个重大的误解.考虑:

  1. 您创建并注册ServerSocketChannelfor OP_ACCEPT.
  2. 两个客户端同时连接.
  3. 现在只有一个SelectionKey存在,因此在选择键集中恰好有一个:那个ServerSocketChannel.
  4. 然后,您isAcceptable()在该密钥上处理您的案例; 接受一个或两个连接; 注册那些频道OP_READ.
  5. 现在有三个选择键,并且在选择键集中没有,因为您清除了它.
  6. 两个客户端都发送一些数据.
  7. 现在,您已准备好在选定键组中读取两个选择键.

好?

我可以简单地执行以下操作:

当然,但为什么呢?通过简单的东西制造复杂的东西是没有好处的.这是第一种方式.

  • 我的天啊。***没有***两种类型的钥匙,而且我在任何地方都没有说过别的。我说“客户端密钥”*指的是不存在的东西。*有*一种*类型的密钥:“SelectionKey”。有两种类型的*通道。*“ServerSocketChannel”和“SocketChannel”。我不知道。我认为这一切都不会被理解。你在某个地方有一个***严重的***误解,但我无法指出它。 (2认同)