nginx http處理過程分析之細節

2021-08-26 16:42:28 字數 2518 閱讀 3059

在之前的綜述中提到過兩篇不錯的部落格,對nginx的http的處理過程分析的很到位,這裡還有一些細節需要拿出來跟大家分享一下。

題外話

在認真思考過每一行**之前,不要說真正理解了它!」 ---(這是我說的,大家覺得搞笑就來噴我吧。-_-!)

這句話實際上是在告訴我們,隱藏在乙份**中的諸多細節,是需要你去仔細翻閱的,許多地方並不是你想當然那樣子的。今天在乙個群裡討論nginx**的時候,我花了不少時間卻沒有把乙個地方給別人講明白,而事實上,這裡並不是原理有多麼的複雜,而且除了我講述內容的80%是遵循**之外,剩餘那20%是想當然的東西。當我再次紮進**中,卻發現了**作者對自己的嘲諷,「其實並不是你想象的那樣子,年輕人!」,到底發生了什麼呢?

某同學問道: 為什麼ngx_http_read_request_header會呼叫ngx_handle_read_event呢?

當時提問的同學在抱怨,「不知道為什麼他還要呼叫一次」。

我當時的反映想當然的認為,可能在某個地方把read event移除了,所以在需要下次繼續讀之前要先註冊乙個讀事件。事實上這種假設合理嗎?但是當時卻是尋著這樣的乙個思路在找**,後來呢?這位同學暈了,我也暈了!到處都是死胡同,講不通。

那問題出在哪兒呢?

「不知道為什麼他還要呼叫一次」,言外之意是前面某處已經新增過事件了?事實上這位同學跟我一樣,犯了想當然的毛病。可惜啊,當我發現這一點的時候,已經耗費了不少時間。那麼我們尋著這個思路追究下去,會不會有合理的解釋呢,為什麼這裡會呼叫ngx_handle_read_event

為了這個問題,我翻開了這個請求的處理歷程,縷一縷到這之前都發生過什麼。

1. 在配置解析結束的前夕,會為每個配置的listen埠申請乙個ngx_listening_t結構,同時設定乙個響應的處理函式:ls->handler = ngx_http_init_connection;

2. 在ngx_event_process_init裡面,為每乙個listen fd從連線池中獲取乙個ngx_connection_t結構,這個結構中有個讀事件結構rev = c->read;而這個讀事件中的乙個handler被設定為rev->handler = ngx_event_accept;

3. 在處理連線之前我們需要首先將listen fd新增到epoll中,在ngx_trylock_accept_mutex中我們看到當乙個程序獲得了accept鎖之後,就通過ngx_enable_accept_events將該listen fd新增進epoll裡面,ngx_add_event(c->read, ngx_read_event, 0),而第三個引數為0,也就意味著,listen fd是以lt模式註冊的,而之後讀請求資料則是et模式註冊的epoll事件,也促成了ngx_event_accept中可以自由控制accept的數量,accept呼叫指定次數之後,可以自由放棄accept,而均衡地交給其他程序來accept,若不是lt,那麼一旦該程序自主放棄accept(即沒有發生eagain),其他程序就得不到epoll的通知了。

4. 一般情況下accept返回的fd是需要放到epoll中的,nginx在accept完成之後卻沒有這麼去做,即使在ls->handler(c),即ngx_http_init_connection的呼叫中,也只是簡單的設定rev->handler = ngx_http_init_request,最終的事件並沒有註冊到epoll裡面。由於一般都是使用ngx_use_accept_mutex,所以通過ngx_post_event(rev, &ngx_posted_events),將剛才封裝的讀事件結構(而非真正的讀事件)加到ngx_posted_events裡面。

5.在ngx_event_process_posted(cycle, &ngx_posted_events)裡面,含有我們在accept裡面封裝的讀事件,注意這個讀事件所在連線的fd是accept返回的,而當ngx_event_process_posted中執行ev->handler(ev)時,ngx_http_init_request就會被呼叫了。

6. 在ngx_http_init_request裡面,設定了rev->handler = ngx_http_process_request_line。但是到目前為止,還沒有對accept獲得的新fd,註冊讀事件,認識到這點很重要!那麼這個新設定的rev->handler既然還沒有註冊事件,那麼如何才會被呼叫到呢?事實上,在函式的最後,它就是直接調的,rev->handler(rev)。。。。

7. 在ngx_http_process_request_line裡面會呼叫ngx_http_read_request_header來讀請求資料,當然這次的讀資料是沒有通過事件驅動來通知的,只是在這個fd上直接recv,這樣當返回eagain時,之前通過被post event裡面來直接讀資料的過程就結束了,接下來才需要針對該fd註冊真正的et模式的讀事件了,這裡我們終於回到了問題的起點,「為什麼要在這裡呼叫ngx_handle_read_event?」

nginx http處理過程分析之細節

在之前的綜述中提到過兩篇不錯的部落格,對nginx的http的處理過程分析的很到位,這裡還有一些細節需要拿出來跟大家分享一下。題外話 在認真思考過每一行 之前,不要說真正理解了它!這是我說的,大家覺得搞笑就來噴我吧。這句話實際上是在告訴我們,隱藏在乙份 中的諸多細節,是需要你去仔細翻閱的,許多地方並...

分析system call中斷處理過程

linux 核心分析 mooc課程 上一次的實驗中,我們選擇了乙個系統呼叫即系統呼叫函式system write函式,分別使用庫函式 api即 printf 函式和c 中嵌入彙編 的方式進行了系統呼叫。我們先複習一下系統呼叫的原理和系統呼叫的過程。首先我們看一下課堂上孟寧老師給出的 系統呼叫三層皮 ...

分析system call中斷處理過程

攥寫人 李鵬舉 學號 20132201 學習課程 linux核心分析 mooc課程 實驗要求 使用gdb跟蹤分析乙個系統呼叫核心函式 您上週選擇那乙個系統呼叫 系統呼叫列表參見 推薦在實驗樓linux虛擬機器環境下完成實驗。根據本週所學知識分析系統呼叫的過程,從system call開始到iret結...