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

java nio select和linux epoll之间有什么区别?

邢飞鸿
2023-03-14

java nio select的代码和linux epoll的代码看起来是一样的。没有循环来获取套接字fd,linux选择代码片段确实使用循环来获取套接字fd。

所以我的问题是,java nio select和linux epoll的方式相同吗?

java nio选择


        while (true) {
            try {
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                selectionKeys.forEach((selectionKey) -> {
                    final SocketChannel client;
                    try {
                        if (selectionKey.isAcceptable()) {
                            ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel();
                            client = server.accept();
                            client.configureBlocking(false);
                            client.register(selector, SelectionKey.OP_READ);

                            String key = "[" + UUID.randomUUID().toString() + "]";

                            clientMap.put(key, client);
                        } else if (selectionKey.isReadable()) {
                            client = (SocketChannel) selectionKey.channel();

                            ByteBuffer readBuffer = ByteBuffer.allocate(1024);

                            int count = client.read(readBuffer);
                            if (count > 0) {
                                //...
                            }

                        }
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                });

                selectionKeys.clear();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

linux e轮询

   for (;;) {
        nfds = epoll_wait(epfd, events, 20, 500);

        for (i = 0; i < nfds; ++i) {
            if (events[i].data.fd == listenfd)

            {
                connfd = accept(listenfd, (sockaddr *) &clientaddr, &clilen);
                if (connfd < 0) {
                    perror("connfd<0");
                    exit(1);
                }
                //setnonblocking(connfd);

                char *str = inet_ntoa(clientaddr.sin_addr);
                ev.data.fd = connfd;

                ev.events = EPOLLIN | EPOLLET;

                epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
            } else if (events[i].events & EPOLLIN)

            {
                cout << "EPOLLIN" << endl;
                if ((sockfd = events[i].data.fd) < 0)
                    continue;
                if ((n = read(sockfd, line, MAXLINE)) < 0) {
                    if (errno == ECONNRESET) {
                        close(sockfd);
                        events[i].data.fd = -1;
                    } else
                        std::cout << "readline error" << std::endl;
                } else if (n == 0) {
                    close(sockfd);
                    events[i].data.fd = -1;
                }
                line[n] = '/0';
                cout << "read " << line << endl;

                ev.data.fd = sockfd;

                ev.events = EPOLLOUT | EPOLLET;

                //epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);

            } else if (events[i].events & EPOLLOUT) 
            {
                sockfd = events[i].data.fd;
                write(sockfd, line, n);

                ev.data.fd = sockfd;

                ev.events = EPOLLIN | EPOLLET;

                epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
            }
        }
    }

linux选择


    for (;;) {
        rset = allset;        /* structure assignment */
        nready = select(maxfd + 1, &rset, NULL, NULL, NULL);

        if (FD_ISSET(listenfd, &rset)) /* new client connection */
        {
            clilen = sizeof(cliaddr);
            connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
#ifdef    NOTDEF
            printf("new client: %s, port %d\n",
                    inet_ntop(AF_INET, &cliaddr.sin_addr, 4, NULL),
                    ntohs(cliaddr.sin_port));
#endif

            for (i = 0; i < FD_SETSIZE; i++)
                if (client[i] < 0) {
                    client[i] = connfd;    /* save descriptor */
                    break;
                }
            if (i == FD_SETSIZE) {
                printf("too many clients");
                exit(0);
            }

            FD_SET(connfd, &allset);    /* add new descriptor to set */
            if (connfd > maxfd)
                maxfd = connfd;            /* for select */
            if (i > maxi)
                maxi = i;                /* max index in client[] array */

            if (--nready <= 0)
                continue;                /* no more readable descriptors */
        }

        for (i = 0; i <= maxi; i++)    /* check all clients for data */
        {
            if ((sockfd = client[i]) < 0)
                continue;
            if (FD_ISSET(sockfd, &rset)) {
                if ((n = read(sockfd, buf, MAXLINE)) == 0)/* connection closed by client */
                {
                    close(sockfd);
                    FD_CLR(sockfd, &allset);
                    client[i] = -1;
                } else
                    write(sockfd, buf, n);

                if (--nready <= 0)
                    break;                /* no more readable descriptors */
            }
        }
    }

共有1个答案

厍晋鹏
2023-03-14

JAVA NIO是JAVA对非阻塞io的抽象。在不同的平台上会有不同的底层实现。在Linux上,它是使用epool实现的。在其他平台上,使用了其他技术,如kqueue。

这使得NIO与epoll非常相似,但java希望您学习其NIO抽象,而不必关心底层实现。

 类似资料:
  • 问题内容: 在此示例中: 无法编译为: 而被编译器接受。 这个答案说明唯一的区别是,与不同,它允许您稍后引用类型,似乎并非如此。 是什么区别,并在这种情况下,为什么不第一编译? 问题答案: 通过使用以下签名定义方法: 并像这样调用它: 在jls§8.1.2中,我们发现(有趣的部分被我加粗了): 通用类声明定义了一组参数化类型(第4.5节), 每种可能通过类型arguments调用类型参数节的类型

  • 问题内容: 今天,我按照一些说明在Linux中安装软件。有一个脚本需要首先运行。它设置一些环境变量。 指令告诉我要执行,但是我执行错误了。因此未设置环境。最后,我注意到了这一点并继续进行。 我想知道这两种调用脚本方法的区别。我对Linux完全陌生,所以请尽可能详细。 问题答案: 运行脚本,将启动一个新的运行脚本的外壳。新的外壳程序不会影响启动脚本的父外壳程序。 是的简写形式,它将在当前shell中

  • 问题内容: 我刚开始使用Spring。我遇到了很多教程。我看到使用更多的例子比。我查看了Spring文档,但无法弄清楚使用其中一个的好处。有人可以提供一些解释吗? 问题答案: 是的便捷子类。 JavaDoc描述了一些添加的属性,这些属性在某些情况下可能有用: UrlBasedViewResolver的便利子类,它支持InternalResourceView(即Servlet和JSP)以及诸如Jst

  • 问题内容: 我刚刚看到了包含标签的CSS代码。我看着MDN看看是什么,但我真的不明白。 有人可以解释它是如何工作的吗? 它会在我们通过CSS选择之前创建DOM元素吗? 问题答案: 根据这些文档,它们是等效的: 唯一的区别是CSS3中使用了双冒号,而单冒号是旧版本。 推理: CSS 3中引入了:: before表示法,以便在伪类和伪元素之间建立区别。浏览器还接受:在CSS 2中引入的表示法。

  • 问题内容: 以下哪个更好? 要么 我知道的唯一区别是,当“ a”为null时,第一个返回false,而第二个抛出异常。除此之外,它们是否总是给出相同的结果? 问题答案: 使用时,你需要B在编译时知道类。使用时可以是动态的,并且可以在运行时更改。

  • 问题内容: 根据MDN: 在许多情况下,revert关键字的工作原理与未设置的关键字完全相同。唯一的区别是属性具有由浏览器或用户创建的自定义样式表(在浏览器侧设置)设置的值。 我不了解浏览器和自定义样式表。浏览器和自定义样式表也都可以替换,对吗? 问题答案: 从MDN: 如果未设置CSS关键字从其父级继承,则将其重置为继承的属性,如果不是,则将其重置为初始值。换句话说,在第一种情况下,其行为类似于

  • 问题内容: 从文档中,我们可以了解有关该功能的以下信息: 处理所有待处理的事件,调用事件回调,完成所有待处理的几何图形管理,根据需要重新绘制窗口小部件,并调用所有待处理的空闲任务。此方法应谨慎使用,因为如果从错误的位置(例如,从事件回调内部,或者从可以以任何方式从事件回调中调用的函数等)调用,则可能导致真正令人讨厌的竞争状况。 )。如有疑问,请改用。 另一方面,关于此功能: 调用所有待处理的空闲任

  • 问题内容: 和CSS 之间有什么区别?可以使用吗? 我看到不同的开发人员在这两种方式上都这样做,而且由于我是自学成才的,所以我从来没有真正想过。 问题答案: 必须是唯一的,才能应用于许多事物。在CSS中,看起来像和元素看起来像 通常,只要您要引用特定元素,并且在有很多相似的事物时使用。举例来说,常见的元素之类的东西,,。常见元素是或。 但是,您应该了解的最基本的优先级是选择器优先于选择器。如果您有