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都是非阻塞模式,並且有各自對應的通知訊息型別