当前位置: 首页 > 知识库问答 >
问题:

java nio ServerSocketChannel accept是如何工作的?

王君墨
2023-03-14

我不明白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()返回一个ServerSocketChannel,它和我们用ServerSocketChannel.open()创建的通道完全一样吗?如果不是,那是什么?
  • 更重要的问题:在大多数其他教程selKey.channel();步骤被跳过,他们只是使用SocketChannel客户端=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()如何知道我们处理的当前密钥?
  • 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);
    }
    
  • 共有1个答案

    周作人
    2023-03-14

    selKey.channel()返回一个ServerSocketChannel,它与我们在开始使用ServerSocketChannel.open()创建的通道完全相同吗?

    更重要的问题:在大多数其他教程中,selKey。通道();跳过这一步,他们只需使用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那么,服务器是如何工作的呢。accept()知道我们处理的当前密钥吗?

    事实并非如此。他们假设只有一个服务器socketchannel。你的方式更好:更一般。

    在里面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的关系。

    方法html" target="_blank">返回积压队列中的下一个套接字,并在积压队列非空时触发OP_ACCEPT。这非常简单,一点也不神秘。顺序根本不“与选定的键相关”。选定的键是ServerSocketChannel的键。

    编辑:看来你有一个很大的误解。考虑:

    1. 您为OP_ACCEPT
    2. 创建并注册一个ServerSocketChannel
    3. 两个客户端同时连接。
    4. 现在正好有一个SelectionKey存在,因此在选定的键集中正好有一个:ServerSocketChannel的键。
    5. 然后,在该键上处理您的isAcctable()大小写;接受一个或两个连接;为OP_READ注册这些通道。
    6. 现在存在三个选择键,并且在选择键集中没有,因为您清除了它。
    7. 两个客户端都发送一些数据。
    8. 现在您有两个选择键准备好在选定的键集中读取。

    好啊

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

    当然,但是为什么?把简单的东西变成复杂的东西是没有好处的。用第一种方法做。

     类似资料:
    • 应用程序具有上下文路径-->/spring-form-simple-project 因此,为了访问,我使用: 这个控制器又返回student.jsp,当提交这个student.jsp时,它用-->@RequestMapping(value=“/AddStudent”,method=RequestMethod.post)调用controller 任何关于这通常如何工作的指示都将是有帮助的。 谢谢!

    • 本文向大家介绍hibernate 是如何工作的?相关面试题,主要包含被问及hibernate 是如何工作的?时的应答技巧和注意事项,需要的朋友参考一下 读取并解析配置文件。 读取并解析映射文件,创建 SessionFactory。 打开 Session。 创建事务。 进行持久化操作。 提交事务。 关闭 Session。 关闭 SessionFactory。

    • 我很想知道谷歌应用商店服务中的Activity认可是如何工作的? 我认为活动是通过加速计数据识别的。是这样吗?。请告诉我详细情况如何

    • 我对GridBagLayout这一主题不熟悉,我无法理解约束、重量和填充之间的确切区别。 我可以而不分配。 除非您指定了至少一个非零值,否则所有组件都会聚集在其容器的中心。这是因为当权重为0.0(默认值)时,GridBagLayout会在其单元格网格和容器边缘之间放置任何额外的空间。 我的问题是,如果这是真的,那么为什么组件之间没有空间,它们看起来是连接的?

    • 从@mock和@injectmocks之间的差异,我理解@injectmocks被用作创建实例的注释,并将用@mock创建的mock注入其中。我想我不明白它是怎么工作的。 以下是我的问题: 在中,当我调用时,它返回一个空集...我的问题是:为什么不抛出(只声明mockedappoinceptions)?也许因为这是一个嘲弄?如果原因是这样,为什么模拟不抛出“NullPointerException

    • 这可能是一个很难回答的问题。我才刚开始学Java 我不懂paintComponent方法的操作。我知道如果我想画一些东西,我必须重写paintComponent方法。

    • 我观看了Walter Brown在Cppcon14上关于现代模板编程的演讲(第一部分,第二部分),他介绍了他的SFINAE技术。 示例: 给定一个简单的变量模板,如果所有模板参数都格式良好,则计算结果为: 存在 格式良好 有效,并计算为 2. 不存在 格式错误,以静默方式失败(sfinae) ,因此丢弃此模板

    • 那么实际上是如何工作的呢?