1. 程式人生 > >nginx中的阻塞和非阻塞設定

nginx中的阻塞和非阻塞設定

縱然對於select,epoll這2個模型,既可以使用阻塞模式的socket也可以使用非阻塞的

雖然,但是這2個模型的訊息通知可以防止accetp,recv在阻塞模式下的進入阻塞狀態,卻不能防止NGINX主動發出的connect和send進入阻塞狀態

特別是NGINX是單執行緒模型,任何呼叫的阻塞狀態都會造成整個執行緒阻塞甚至掛起,這對NGINX來說是完全不能接受的

因此在ngx_open_listening_sockets函式中,對所有listen socket,除非是IOCP或者UNIX_AIO模型,都把這個socket設定成非阻塞模式,程式碼如下:

            if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) {
                if (ngx_nonblocking(s) == -1) {
                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                                  ngx_nonblocking_n " %V failed",
                                  &ls[i].addr_text);


                    if (ngx_close_socket(s) == -1) {
                        ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                                      ngx_close_socket_n " %V failed",
                                      &ls[i].addr_text);
                    }


                    return NGX_ERROR;
                }
            }

而在ngx_event_accept中,也有一樣的實現邏輯

        /* set a blocking mode for aio and non-blocking mode for others */


        if (ngx_inherited_nonblocking) {
            if (ngx_event_flags & NGX_USE_AIO_EVENT) {
                if (ngx_blocking(s) == -1) {
                    ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                  ngx_blocking_n " failed");
                    ngx_close_accepted_connection(c);
                    return;
                }
            }


        } else {
            if (!(ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT))) {
                if (ngx_nonblocking(s) == -1) {
                    ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                  ngx_nonblocking_n " failed");
                    ngx_close_accepted_connection(c);
                    return;
                }
            }
        }

比較特殊的是connect,unix平臺的傳統的做法都是讓connect的socket進入非阻塞模式,NGINX也是這樣,在ngx_event_connect_peer中,直接設定成非阻塞模式了事

    if (ngx_nonblocking(s) == -1) {
        ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
                      ngx_nonblocking_n " failed");


        goto failed;
    }

另外補充一點,win平臺上的WsaAysncSelect以及WsaEventSelect會自動把套介面設定成非阻塞模式,因此不管connect,send,accept,recv都是非阻塞模式,並且有各自對應的通知訊息型別