nginx epoll與read write事件

epoll原理

n = epoll_wait(epfd,events,20,500);

for(i=0;i<n;++i)

{

c = event_list[i].data.ptr;

c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~3);

 

 

/* 連接有可讀事件,且該讀事件是active活躍的 */

    if ((revents & EPOLLIN) && rev->active) {

     rev = c->read;

/*

                 * 這裏要區分active與ready:

                 * active是指事件被添加到epoll對象的監控中,

                 * 而ready表示被監控的事件已經準備就緒,即可以對其進程IO處理;

                 * 讀事件的ready代表有數據可以接受處理,寫事件的ready代表buffer有空間可寫

*/

rev->ready = 1;

/*

             * NGX_POST_EVENTS表示已準備就緒的事件需要延遲處理,

             * 根據accept標誌位將事件加入到相應的隊列中;

             */

if (flags & NGX_POST_EVENTS) {

                queue = rev->accept ? &ngx_posted_accept_events

                                    : &ngx_posted_events;

                ngx_post_event(rev, queue);

 

            } else {

/* 若不延遲處理,則直接調用事件的處理函數 */

                rev->handler(rev);

            }

}

}

// write事件同理

}

 

 

 

每個event在rev→ready設置爲1之後,需要進行io處理。

ssize_t

ngx_unix_send(ngx_connection_t *c, u_char *buf, size_t size)

{

...

for ( ;; ) {

        n = send(c->fd, buf, size, 0);

 

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,

                       "send: fd:%d %z of %uz", c->fd, n, size);

 

        if (n > 0) {

            if (n < (ssize_t) size) {

// 發送的數據大小大於0,小於n,說明未發送完成,wev->ready置爲0,此次發送結束,下次繼續調用write事件進行發送。

                wev->ready = 0;

            }

 

            c->sent += n;

 

            return n;

        }

}

...

}

 

 

 

 

ssize_t

ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size)

{

...

do {

        n = recv(c->fd, buf, size, 0);

 

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,

                       "recv: fd:%d %z of %uz", c->fd, n, size);

 

        if (n == 0) {

// 無可接受數據,此次讀事件結束,ready置0

            rev->ready = 0;

            rev->eof = 1;

}

...

}

每次的讀事件,是該fd的讀buffer上有數據被寫入,引發epollin,如果是水平觸發,只要有數據就會一直觸發這個讀事件,如果是邊緣觸發,就會等到新的數據被寫入纔會觸發該事件,因此在面對高性能的邊緣觸發中,一定要注意數據的接收,每次用while true讀完,不然一旦有殘留,需要等下個包到達才能取出。

每次的寫事件很難被觸發,因爲正常都會被直接發送完成,只有發送一部分數據,寫buffer就滿了的情況下,epoll會監聽該事件,一旦寫隊列緩衝區有空間,可寫,纔會觸發新的寫事件,將數據發送完成。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章