WebサーバとしてのNginxの調査結果を記録する。


ngx_event_accept関数

epoll_waitでファイルディスクリプタに新規接続が来たことがわかります。
この関数でaccept()します。


     17 void
     18 ngx_event_accept(ngx_event_t *ev)
     19 {
     20     socklen_t          socklen;
     21     ngx_err_t          err;
     22     ngx_log_t         *log;
     23     ngx_socket_t       s;
     24     ngx_event_t       *rev, *wev;
     25     ngx_listening_t   *ls;
     26     ngx_connection_t  *c, *lc;
     27     ngx_event_conf_t  *ecf;
     28     u_char             sa[NGX_SOCKADDRLEN];
     29
     30     ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);
     31
     32     if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
     33         ev->available = 1;
     34
     35     } else if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) {
     36         ev->available = ecf->multi_accept;
     37     }
     38
     39     lc = ev->data;
     40     ls = lc->listening;
     41     ev->ready = 0;
     42
     43     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
     44                    "accept on %V, ready: %d", &ls->addr_text, ev->available);
     45
     46     do {
     47         socklen = NGX_SOCKADDRLEN;
     48
     49         s = accept(lc->fd, (struct sockaddr *) sa, &socklen);
     50
     51         if (s == -1) {
     52             err = ngx_socket_errno;
     53
     54             if (err == NGX_EAGAIN) {
     55                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err,
     56                                "accept() not ready");
     57                 return;
     58             }
     59
     60             ngx_log_error((ngx_uint_t) ((err == NGX_ECONNABORTED) ?
     61                                              NGX_LOG_ERR : NGX_LOG_ALERT),
     62                           ev->log, err, "accept() failed");
     63
     64             if (err == NGX_ECONNABORTED) {
     65                 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
     66                     ev->available--;
     67                 }
     68
     69                 if (ev->available) {
     70                     continue;
     71                 }
     72             }
     73
     74             return;
     75         }

accept()とエラー処理です。
特に特筆すべきことはないですね。



     81         ngx_accept_disabled = ngx_cycle->connection_n / 8
     82                               - ngx_cycle->free_connection_n;
     83
     84         c = ngx_get_connection(s, ev->log);
     85
     86         if (c == NULL) {
     87             if (ngx_close_socket(s) == -1) {
     88                 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
     89                               ngx_close_socket_n " failed");
     90             }
     91
     92             return;
     93         }
このコードは・・・何でしょう。
ngx_cycle->connection_nは設定ファイルworker_connectionsの設定。
それを8で割って、空いているコネクションの数で引き算。
ううむ。
次の関数ではaccept()したファイルディスクリプタをngx_connection_t構造体に登録しています。

     99         c->pool = ngx_create_pool(ls->pool_size, ev->log);
    100         if (c->pool == NULL) {
    101             ngx_close_accepted_connection(c);
    102             return;
    103         }
    104
    105         c->sockaddr = ngx_palloc(c->pool, socklen);
    106         if (c->sockaddr == NULL) {
    107             ngx_close_accepted_connection(c);
    108             return;
    109         }
    110
    111         ngx_memcpy(c->sockaddr, sa, socklen);
    112
    113         log = ngx_palloc(c->pool, sizeof(ngx_log_t));
    114         if (log == NULL) {
    115             ngx_close_accepted_connection(c);
    116             return;
    117         }
pool・・・名前からしてApacheと同じでしょう。
煩わしいメモリ管理はpoolを使う点は変わらないのですね。
poll領域作成、accept()によって接続先のアドレス情報が格納された情報をc->sockaddrにセットです。


    119         /* set a blocking mode for aio and non-blocking mode for others */
    120
    121         if (ngx_inherited_nonblocking) {
    122             if (ngx_event_flags & NGX_USE_AIO_EVENT) {
    123                 if (ngx_blocking(s) == -1) {
    124                     ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
    125                                   ngx_blocking_n " failed");
    126                     ngx_close_accepted_connection(c);
    127                     return;
    128                 }
    129             }
    130
    131         } else {
    132             if (!(ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT))) {
    133                 if (ngx_nonblocking(s) == -1) {
    134                     ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
    135                                   ngx_nonblocking_n " failed");
    136                     ngx_close_accepted_connection(c);
    137                     return;
    138                 }
    139             }
    140         }
コメントの通り、らしいです。
AIOを使う場合はブロッキングモード、そうではない場合ノンブロッキングモード。
AIOはまだ勉強していないんだよな・・・。
手元のCentOSの場合は、ノンブロッキングモードなのでAIOは自分の課題とします。

    142         *log = ls->log;
    143
    144         c->recv = ngx_recv;
    145         c->send = ngx_send;
    146         c->recv_chain = ngx_recv_chain;
    147         c->send_chain = ngx_send_chain;
    148
    149         c->log = log;
    150         c->pool->log = log;
    151
    152         c->socklen = socklen;
    153         c->listening = ls;
    154         c->local_sockaddr = ls->sockaddr;
    155         c->local_socklen = ls->socklen;
    156
    157         c->unexpected_eof = 1;
    158
    159         rev = c->read;
    160         wev = c->write;
    161
    162         wev->ready = 1;
    163
    164         if (ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT)) {
    165             /* rtsig, aio, iocp */
    166             rev->ready = 1;
    167         }
    168
    169         if (ev->deferred_accept) {
    170             rev->ready = 1;
    171 #if (NGX_HAVE_KQUEUE)
    172             rev->available = 1;
    173 #endif
    174         }
    175
    176         rev->log = log;
    177         wev->log = log;
accept()したファイルディスクリプタが入ったngx_connection_t構造体にガシガシ初期値を格納。
コネクションの処理では、ngx_connection_t構造体が肝になるのでしょう。

ngx_recvやngx_sendって何だ!?と思ったらngx_event.hにありました。
extern ngx_os_io_t  ngx_io;

#define ngx_recv             ngx_io.recv
#define ngx_recv_chain       ngx_io.recv_chain
#define ngx_udp_recv         ngx_io.udp_recv
#define ngx_send             ngx_io.send
#define ngx_send_chain       ngx_io.send_chain
ngx_os_io_t構造体はngx_os.hにあってこんな感じ
typedef struct {
    ngx_recv_pt        recv;
    ngx_recv_chain_pt  recv_chain;
    ngx_recv_pt        udp_recv;
    ngx_send_pt        send;
    ngx_send_chain_pt  send_chain;
    ngx_uint_t         flags;
} ngx_os_io_t;

Linuxの場合はngx_linux_init.cでngx_os_io_t構造体の値を定義していました。
static ngx_os_io_t ngx_linux_io = {
    ngx_unix_recv,
    ngx_readv_chain,
    ngx_udp_unix_recv,
    ngx_unix_send,
#if (NGX_HAVE_SENDFILE)
    ngx_linux_sendfile_chain,
    NGX_IO_SENDFILE
#else
    ngx_writev_chain,
    0
#endif
};



    179         /*
    180          * TODO: MT: - ngx_atomic_fetch_add()
    181          *             or protection by critical section or light mutex
    182          *
    183          * TODO: MP: - allocated in a shared memory
    184          *           - ngx_atomic_fetch_add()
    185          *             or protection by critical section or light mutex
    186          */
    187
    188         c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
    189
    190 #if (NGX_STAT_STUB)
    191         (void) ngx_atomic_fetch_add(ngx_stat_handled, 1);
    192 #endif
    193
    194 #if (NGX_THREADS)
    195         rev->lock = &c->lock;
    196         wev->lock = &c->lock;
    197         rev->own_lock = &c->lock;
    198         wev->own_lock = &c->lock;
    199 #endif
    200
    201         if (ls->addr_ntop) {
    202             c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len);
    203             if (c->addr_text.data == NULL) {
    204                 ngx_close_accepted_connection(c);
    205                 return;
    206             }
    207
    208             c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->addr_text.data,
    209                                              ls->addr_text_max_len, 0);
    210             if (c->addr_text.len == 0) {
    211                 ngx_close_accepted_connection(c);
    212                 return;
    213             }
    214         }
    215
    216 #if (NGX_DEBUG)
    217         {
    218
    219         in_addr_t            i;
    220         ngx_event_debug_t   *dc;
    221         struct sockaddr_in  *sin;
    222
    223         sin = (struct sockaddr_in *) sa;
    224         dc = ecf->debug_connection.elts;
    225         for (i = 0; i < ecf->debug_connection.nelts; i++) {
    226             if ((sin->sin_addr.s_addr & dc[i].mask) == dc[i].addr) {
    227                 log->log_level = NGX_LOG_DEBUG_CONNECTION|NGX_LOG_DEBUG_ALL;
    228                 break;
    229             }
    230         }
    231
    232         }
    233 #endif
    234
    235         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0,
    236                        "*%d accept: %V fd:%d", c->number, &c->addr_text, s);
    237
    238         if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
    239             if (ngx_add_conn(c) == NGX_ERROR) {
    240                 ngx_close_accepted_connection(c);
    241                 return;
    242             }
    243         }
    244
    245         log->data = NULL;
    246         log->handler = NULL;
    247
    248         ls->handler(c);
    249
    250         if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
    251             ev->available--;
    252         }
    253
    254     } while (ev->available);
    255 }
201行目からの処理は、たぶんIPアドレスを取得してngx_connection_t構造体にセットしていると思われます。
デバック処理を経て、ls->handler(c);よりngx_http_init_connection()へ。

次はngx_http_init_connectionを見ます。

このページへのコメント

yxX9K7 <a href="http://bygieopvkskd.com/">bygieopvkskd</a>, [url=http://nswlapglxbzw.com/]nswlapglxbzw[/url], [link=http://ribatezajhig.com/]ribatezajhig[/link], http://eleitvnvhmzx.com/

0
Posted by drnfupy 2013年11月14日(木) 10:30:26 返信

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu

メニューサンプル1

メニューサンプル2

開くメニュー

閉じるメニュー

  • アイテム
  • アイテム
  • アイテム
【メニュー編集】

管理人/副管理人のみ編集できます