Nginx 是一個事件驅動的框架,所謂事件主要指的是網路事件,Nginx 每個網路連接會對應兩個網路事件,一個讀事件一個寫事件,在深入了解 Nginx 各種原理及在極端場景下的一些錯誤場景處理時,需要首先理解什么是網路事件,
網路傳輸

接下來看上面這張圖,比如主機 A 就是一臺家里的筆記本電腦,那么主機 B 就是一臺服務器,上面跑著 Nginx 服務,從主機 A 發送一個 HTTP 的 GET 請求到主機 B,這樣的一個程序中主要經歷了哪些事件?通過上圖資料流部分可以看出:
應用層里發送了一個 GET 請求 -> 到了傳輸層,這一步主要在做一件事,就是瀏覽器打開了一個埠,在 windows 的任務管理器中可以看到這一點,他會把這個埠記下來以及把 Nginx 打開的埠比如 80 或者 443 也記到傳輸層 -> 然后在網路層會記下我們主機所在的 IP 和目標主機,也就是 Nginx 所在服務器公網 IP -> 到鏈路層以后 -> 經過以太網 -> 到達家里的路由器(網路層),家中的路由器會記錄下所在運營商的一些下一段的 IP -> 通過廣域網 -> 跳轉到主機 B 所在的機器中 -> 報文會經過鏈路層 -> 網路層 -> 到傳輸層,在傳輸層作業系統就知道是給那個打開了 80 或者 443 的行程,這個行程自然就是 Nginx -> 那么 Nginx 在他的 HTTP 狀態處理機里面(應用層)就會處理這個請求,
在上述程序中網路報文扮演了一個怎樣的角色呢?
TCP流與報文

資料鏈路層會在資料的前面 Header 部分和 Footer 部分添加上源 MAC 地址和源目的地址 -> 到了網路層則是 Nginx 的公網地址(目的 IP 地址)和瀏覽器的公網地址(源 IP 地址)-> 到了 TCP 層(傳輸層),指定了 Nginx 打開的埠(目的埠)和瀏覽器打開的埠(源埠)-> 然后應用層就是 HTTP 協議了,
這就是一個報文,也就是說我們發送的 HTTP 協議會被切割成很多小的報文,在網路層會切割叫 MTU,以太網的每個 MTU 是 1500 位元組;在 TCP 層(傳輸層)呢會考慮中間每個環節中最大的一個 MTU 值,這個時候往往每個報文只有幾百位元組,這個報文大小我們稱為叫 MSS ,所以每收到一個 MSS 小于這么大小的一個報文時其實就是一個網路事件,
這個時候,我們來看下 TCP 協議中許多事件是怎樣和我們日常呼叫的一些介面(比如 Accept、Read、Write、Close)是怎樣關聯在一起的?
TCP 協議與非阻塞介面

請求建立 TCP 連接事件實際上是發送了一個 TCP 報文,通過上面第二部分講解的那樣的一個流程到達了 Nginx,對應的是讀事件,因為對于 Nginx 來說,我讀取到了一個報文,所以就是 Accept 建立鏈接事件,
如果是 TCP 連接可讀事件,就是發送了一個訊息,對于 Nginx 也是一個讀事件,就是 Read 讀訊息,
如果是對端(也就是瀏覽器)主動地關掉了,相當于 windows 作業系統會去發送一個要求關閉鏈接的一個事件,對于 Nginx 來說還是一個讀事件,因為他只是去讀取一個報文,
那什么是寫事件呢?當我們的瀏覽器需要向瀏覽器發送回應的時候,需要把訊息寫到作業系統中,要求作業系統發送到網路中,這就是一個寫事件,
像這樣的一些網路讀寫事件,通常在 Nginx 中或者任何一個異步事件的處理框架中,他會有個東西叫事件收集、分發器,會定義每類事件處理的消費者,也就是說事件是一個生產者,是通過網路中自動的生產到我們的 Nginx 中的,我們要對每種事件建立一個消費者,比如連接建立事件消費者,就是對 Accept 呼叫,HTTP 模塊就會去建立一個新的連接,還有很多讀訊息或者寫訊息,在 HTTP 狀態機中不同的時間段會呼叫不同的方法也就是每個消費者處理,
以上就是一個事件分發、消費器,包括 AIO 像異步讀寫磁盤事件,還有定時器事件,比如是否超時(worker_shutdown_timeout),
Nginx 網路事件實體
上面介紹了網路報文的發送以及對應的 Nginx 中的網路事件,比如 Accept 建立一條新連接其實是收到一條讀事件,接下來我們通過抓包來分析建立三次握手時時怎么樣讓 Nginx 收到讀事件,使用的抓包工具是 Wireshark,

首先我們安裝 Wireshark 軟體,并對 Nginx 所在 IP 和埠進行抓包,然后訪問頁面,在 TCP 層主要說兩件事情:
- 瀏覽器首先會打開這個頁面,本地打開了一個 1875 埠,而 Nginx 啟動的是 8080 埠,
- TCP 層主要做的是行程與行程之間通訊這件事,

IP 層主要解決機器與機器之間怎樣互相找到的問題,

三次握手也就是 windows 先向 Nginx 發送了一次 [SYN],那么相反的 Nginx 所在的服務器也會向 windows 發送一個 [SYN],這個時候 Nginx 是沒有感知到的,因為這個連接還是處于半打開的狀態,直到這臺 windows 服務器再次發送 [ACK] 到 Nginx 所在的服務器之上時,Nginx 所在的作業系統才會去通知 Nginx 我們收到了一個讀事件,這個讀事件對應是建立一個新連接,所以此時 Nginx 應該呼叫 Accept 方法去建立一個新的連接,

以上我們通過 Wireshark 抓包演示了正常的三次握手是怎么樣引發一個讀事件來使得 Nginx 去處理這樣一個讀事件來建立新的連接的,
總結
這篇文章主要講解了網路事件,并通過抓包來分析 Nginx 網路事件,這對我們理解 Nginx 異步處理框架是非常有幫助的,包括 OpenResty 也是強依賴于網路事件以及事件分發的,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/98355.html
標籤:其他
上一篇:socket編程因who has 192.168.1.123 ? Tell 0.0.0.0 導致通訊例外
下一篇:新手報道,多多指教
