简体   繁体   English

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

[英]Why Tomcat's Non-Blocking Connector is using a blocking socket?

I was reading about Non-blocking I/O, java NIO and tomcat connectors, looked at the code of tomcat's NIO Connector, and found this in NioEndpoint.bind() : 我正在阅读非阻塞I / O,java NIO和tomcat连接器,查看了tomcat的NIO Connector的代码,并NioEndpoint.bind()找到了这个

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

I don't have experience with NIO, so can someone explain how it is non-blocking when the socket is configured to be blocking? 我没有NIO的经验,所以有人可以解释当套接字配置为阻塞时它是如何非阻塞的吗?

Looks like the following line was introduced at this commit https://github.com/apache/tomcat/blob/bd8122700c2e70e5adbaddcd289fb1a974f981fe/java/org/apache/tomcat/util/net/NioEndpoint.java 看起来在此次提交中引入了以下行:https://github.com/apache/tomcat/blob/bd8122700c2e70e5adbaddcd289fb1a974f981fe/java/org/apache/tomcat/util/net/NioEndpoint.java

As far as I can tell this is NioEndpoint is using blocking ServerSocketChannel in order for it to block and wait for an incoming connection and only after it accepts it it processes this incoming socket channel in a non-blocking manner (see setSocketOptions method). 据我所知,NioEndpoint正在使用阻塞ServerSocketChannel来阻止和等待传入连接,并且只有在接受它之后才以非阻塞方式处理这个传入套接字通道(请参阅setSocketOptions方法)。

The alternative to make ServerSocketChannel a non-blocking one will result as author points out into a busy read - that is a thread will be constantly polling for incoming connections as accept() in non-blocking mode may return null. 使得ServerSocketChannel成为非阻塞的替代方法将导致作者指出忙读 - 即线程将不断轮询传入连接,因为非阻塞模式下的accept()可能返回null。

You can find some useful explanation here . 你可以在这里找到一些有用的解释。

PS I presume that cryptic APR stands for Apache Portable Runtime. PS我认为神秘的APR代表Apache Portable Runtime。

After reading the code: 看完代码后:

The serverSock object is listening for incoming connections is blocking . serverSock对象正在侦听传入连接是否阻塞 The socket channel object associated with its new accepted connection is the one that implements a non-blocking I/O. 与其新接受的连接关联的socket通道对象是实现非阻塞 I / O的对象。

The Acceptor class that is a thread that listens for incoming connections has the following definition in its run method: 作为侦听传入连接的线程的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);
                    }
                } ....

As you can see it's the setSocketOptions method that processes a new socket and it has the following code: 正如您所看到的那样,它是处理新socketsetSocketOptions方法,它具有以下代码:

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); 

The socket channel object associated with each connection that is used to send/receive data in the endpoints of the corresponding connection is the one that really implements a non-blocking I/O . 与用于在相应连接的端点中发送/接收数据的每个连接相关联的socket通道对象是真正实现non-blocking I/Osocket通道对象。

Although one can always set the serverSock object accept method to be non-blocking, I believe that making the select (ie accept) operation non-blocking would be impractical and would not server any real purpose and would not be useful in any real context. 尽管可以始终将serverSock对象accept方法设置为非阻塞,但我认为将select (即accept)操作设置为非阻塞是不切实际的,并且不会服务于任何实际目的,并且在任何实际上下文中都不会有用。 I could not think of any use case where a non-blocking accept operation would be useful. 我想不出任何非阻塞接受操作有用的用例。 That is for me. 那对我来说。

Non-blocking seen from the point of view of the caller. 从呼叫者的角度看非阻塞。 The API will still need to use blocking (in a worker thread) or asynchronous I/O to actually complete the operation. API仍然需要使用阻塞(在工作线程中)或异步I / O来实际完成操作。 Otherwise the socket will need a spinlock with the resulting CPU soak. 否则,套接字将需要一个自旋锁,并产生CPU浸泡。

You need to look at the remainder of the implementation to see how this mapping is accomplished. 您需要查看实现的其余部分,以了解如何完成此映射。

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

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