简体   繁体   English

java nio ServerSocketChannel如何接受?

[英]How java nio ServerSocketChannel accept works?

I can't get how NIO works under the hood. 我无法理解NIO是如何在幕后工作的。 Here is a sample code: 这是一个示例代码:

// 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();
     }
}

Here I have a couple of questions: 在这里,我有几个问题:

  1. selKey.channel() return a ServerSocketChannel is it exactly the same channel we created in the beggining with ServerSocketChannel.open()? selKey.channel()返回一个ServerSocketChannel它与我们在使用ServerSocketChannel.open()开始创建时完全相同吗? If not, then what is it? 如果没有,那么它是什么?
  2. More important question: in most other tutorials selKey.channel(); 更重要的问题:在大多数其他教程中selKey.channel(); step is skipped and they simply use SocketChannel client = server.accept(); 跳过步骤,他们只使用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? 例如: 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. 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. http://www.developer.com/java/article.php/10922_3837316_2/Non-Blocking-IO-Made-Possible-in-Java.htm中,他们甚至建议在新线程中接受频道。 I guess it is possible that the following situation may occur. 我想有可能发生以下情况。

     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 

So, could you please explain how selector works in pair with ServerSocketChannel and accept method? 那么,您能否解释一下选择器如何与ServerSocketChannel和accept方法配对? Because I don't understand in which order #accept accepts clients and how this order related to selectedKeys. 因为我不明白#accept接受客户端的顺序以及此命令与selectedKeys的关系。

  1. Can I simply do the following: 我可以简单地执行以下操作:

     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()? selKey.channel()返回一个ServerSocketChannel它与我们在ServerSocketChannel.open()开头创建的通道完全相同吗?

Yes. 是。

More important question: in most other tutorials selKey.channel(); 更重要的问题:在大多数其他教程中selKey.channel(); step is skipped and they simply use SocketChannel client = server.accept(); 跳过步骤,他们只使用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? 例如: 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()如何知道我们处理的当前密钥?

It doesn't. 它没有。 They're assuming that there is only one ServerSocketChannel . 他们假设只有一个ServerSocketChannel Your way is better: it's more general. 你的方式更好:它更通用。

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. http://www.developer.com/java/article.php/10922_3837316_2/Non-Blocking-IO-Made-Possible-in-Java.htm中,他们甚至建议在新线程中接受频道。

I have no idea why. 我不知道为什么。 It's a non-blocking call. 这是一个非阻塞的电话。 It will return immediately. 它会立即返回。 The suggestion is pointless. 这个建议毫无意义。 Ignore it. 忽略它。 It's a very poor quality tutorial from six years ago, but there were better ones in existence thirteen years ago. 这是六年前质量很差的教程,但十三年前还有更好的教程。 Try the Oracle tutorial. 试试Oracle教程。 The author of this one doesn't seem to understand the point of non-blocking mode at all. 这个人的作者似乎根本不理解非阻塞模式。 The suggestion to use a separate thread for every event is completely and utterly ludicrous. 为每个事件使用单独的线程的建议是完全和完全荒谬的。 He also doesn't understand how to use OP_WRITE. 他也不明白如何使用OP_WRITE。 He makes a false assertion about cancel() . 他对cancel()做出了错误的断言。 I could go on. 我可以继续 It's doubtful that he has ever executed this code: he certainly didn't investigate its behaviour in any way. 他曾经执行过这段代码是值得怀疑的:他当然没有以任何方式调查其行为。 How to write a non-scalable NIO server. 如何编写不可伸缩的NIO服务器。 Quite a feat. 相当壮举。

I guess it is possible that the following situation may occur. 我想有可能发生以下情况。

I don't even seen why you would be accepting in two threads at the same time, let alone how it could possibly matter to either thread which client it accepts. 我甚至没有看到为什么你会同时接受两个线程,更不用说它们接受哪个客户端的线程。 This is a difficulty invented where none exists. 这是一个难以发明的难点。

So, could you please explain how selector works in pair with ServerSocketChannel and accept method? 那么,您能否解释一下选择器如何与ServerSocketChannel和accept方法配对? Because I don't understand in which order #accept accepts clients and how this order related to selectedKeys. 因为我不明白#accept接受客户端的顺序以及此命令与selectedKeys的关系。

The accept() method returns the next socket in the backlog queue, and OP_ACCEPT fires whenever the backlog queue is non-empty. accept()方法返回积压队列中的下一个套接字,只要积压队列非空,就会触发OP_ACCEPT。 It's perfectly simple, no mystery. 它非常简单,没有神秘感。 The order doesn't 'relate to selected keys' at all. 该订单根本不与“所选密钥相关”。 The selected key is that of the ServerSocketChannel . 所选密钥是ServerSocketChannel密钥。

EDIT: It appears you have a major misunderstanding. 编辑:看来你有一个重大的误解。 Consider: 考虑:

  1. You create and register a ServerSocketChannel for OP_ACCEPT . 您为OP_ACCEPT创建并注册ServerSocketChannel
  2. Two clients connect simultaneously. 两个客户端同时连接。
  3. There is now exactly one SelectionKey in existence, and therefore exactly one in the selected-keys set: that of the ServerSocketChannel . 现在只有一个SelectionKey存在,因此在selected-key集中只有一个: ServerSocketChannel的那个。
  4. You then process your isAcceptable() case on that key; 然后,您在该键上处理isAcceptable()案例; accept one or both connections; 接受一个或两个连接; register those channels for OP_READ. OP_READ.注册这些通道OP_READ.
  5. There are now three selection keys in existence, and none in the selected-key set, because you cleared it. 现在有三个选择键,并且在选择键集中没有,因为您清除了它。
  6. Both the clients send some data. 两个客户端都发送一些数据。
  7. Now you have two selection keys ready to read in the selected-keys set. 现在,您已准备好在选定键组中读取两个选择键。

OK? 好?

Can I simply do the following: 我可以简单地执行以下操作:

Certainly, but why? 当然,但为什么呢? There is no advantage to be had by making something complicated out of something simple. 通过简单的东西制造复杂的东西是没有好处的。 Do it the first way. 这是第一种方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM