为什么Tomcat的非阻塞连接器使用阻塞套接字?

时间:2014-04-19 10:35:04

标签: java tomcat nio

我正在阅读非阻塞I / O,java NIO和tomcat连接器,查看了tomcat的NIO连接器的代码,以及found this in NioEndpoint.bind()

serverSock.configureBlocking(true); //mimic APR behavior

我没有NIO的经验,所以有人可以解释当套接字被配置为阻塞时它是如何非阻塞的吗?

3 个答案:

答案 0 :(得分:2)

在此次提交https://github.com/apache/tomcat/blob/bd8122700c2e70e5adbaddcd289fb1a974f981fe/java/org/apache/tomcat/util/net/NioEndpoint.java

中看起来引入了以下行

据我所知,NioEndpoint正在使用阻塞ServerSocketChannel来阻止和等待传入连接,并且只有在它接受后才以非阻塞方式处理这个传入套接字通道(请参阅setSocketOptions方法) )。

使ServerSocketChannel成为非阻塞的替代方法将导致作者指出忙读 - 这是一个线程将不断轮询传入连接,因为非阻塞模式下的accept()可能返回null。

您可以找到一些有用的解释here

P.S。 我认为神秘的APR代表Apache Portable Runtime。

答案 1 :(得分:1)

阅读完代码后:

serverSock对象正在侦听传入连接阻止。与其新接受的连接关联的socket频道对象是实现非阻止 I / O的连接。

作为侦听传入连接的线程的Acceptor class在其run方法中具有以下定义:

protected class Acceptor extends AbstractEndpoint.Acceptor {
        @Override
        public void run() {
            // Loop until we receive a shutdown command
            while (running) {
                // Loop if endpoint is paused
                while (paused && running) {
                   ...
                try {
                        ........
                    SocketChannel socket = null;
                    try {
                        // Accept the next incoming connection from the server
                        // socket
                        socket = serverSock.accept(); 

                    } catch (IOException ioe) {............}
                ...................
                // setSocketOptions() will add channel to the poller
                // if successful
                if (running && !paused) {
                    if (!setSocketOptions(socket)) {
                        countDownConnection();
                        closeSocket(socket);
                    }
                } ....

正如您所看到的那样,处理新setSocketOptions的{​​{1}}方法具有以下代码:

socket

与用于在相应连接的端点中发送/接收数据的每个连接相关联的protected boolean setSocketOptions(SocketChannel socket) { // Process the connection try { //disable blocking, APR style, we are gonna be polling it socket.configureBlocking(false); Socket sock = socket.socket(); socketProperties.setProperties(sock); 通道对象是真正实现socket的通道对象。

虽然可以始终将non-blocking I/O对象serverSock方法设置为非阻塞,但我认为使accept(即接受)操作无阻塞是不切实际的,并且会不服务于任何真正的目的,并且在任何真实的环境中都没有用。我想不出任何非阻塞接受操作有用的用例。那是给我的。

答案 2 :(得分:0)

从呼叫者的角度看非阻塞。 API仍然需要使用阻塞(在工作线程中)或异步I / O来实际完成操作。否则,套接字将需要一个自旋锁,并产生CPU浸泡。

您需要查看实现的其余部分,以了解如何完成此映射。