[Linux網絡_71] NAT技術 | 正反代理 | 網絡協議總結 | 五種IO模型

目錄

1.NAT技術

NAPT

2.NAT和代理服務器

3.網線通信各層協議總結

補充說明

4.五種 IO 模型

1.什么是IO?什么是高效的IO?

2.有那些IO的方式?這么多的方式,有那些是高效的?

異步 IO

🎣 關鍵缺陷類比

📝 具體技術缺陷

?? 實踐中的坑


多路復用,引入了對多個文件的同時等待,那么對這多個文件的管理,就又可以引入我們的數據結構啦

1.NAT技術

NAT技術背景
之前我們討論了, IPv4協議中, IP地址數量不充足的問題
NAT技術當前解決IP地址不夠用的主要手段, 是路由器的一個重要功能;

  • NAT能夠將私有IP對外通信時轉為全局IP. 也就是就是一種將私有IP和全局IP相互轉化的技術方法:
  • 很多學校, 家庭, 公司內部采用每個終端設置私有IP, 而在路由器或必要的服務器上設置全局IP;
  • 全局IP要求唯一, 但是私有IP不需要; 在不同的局域網中出現相同的私有IP是完全不影響的;

NAT IP轉換過程

之前說過,當進行數據跨網絡傳輸時,構建一個報文向下交付,到網絡層后要經過路由選擇,發現要去目標主機和我并不再同一個子網,所以向下交付封裝MAC幀交付給出口路由器 ,家用路由器的IP地址肯定知道因為你連接過路由器,如果不知道MAC地址就做ARP。

  • 然后出口路由器經過同樣的策略交給下一跳路由器直到交給目標主機。
  • 在整個交付過程中,路由器不僅僅是把報文交給下一跳。
  • 更重要的在交付的時候把源IP地址不斷的做替換
  • 每一個路由器不僅有LAN口IP,還要WAN口IP,當做數據包轉發時,是把源IP替換成路由器的WAN口IP

一路替換然后數據包經過目的主機處理然后返回接下來怎么走呢?

下面我們具體說一下整個過程。

  • 客戶端A、B、C都有自己的私有IP,每臺主機我們要透過現象看本質,每臺機器都有TCP/IP協議棧。
  • 客戶端A將數據經過路由器發送給服務器。
  • 其中路由器本質天然的就包含了NAT地址轉化的功能,所以在數據在剛開始轉發時源IP地址是它自己私有IP,然后經過路由選擇發現要去路由器,到路由器之后就把當前IP報頭中源地址替換成路由器自己的WAN口IP,然后讓路由替這個主機發起網絡請求,最終經過內網和公網轉發這個數據到了服務器。
  • 服務器處理好了根據得到的源IP構建響應返回給NAT路由器,那此時NAT路由器中報文中目的IP目前是202.244.174.37,接下來問題是怎么從這個路由器回到主機。

有人可能說轉化時建立一個映射關系,然后回到NAT路由器在把目的IP轉化一次變成源IP地址不就可以了嗎,但如果是一個局域網主機都訪問同于一個服務器呢?

NAPT

那么問題來了, 如果局域網內, 有多個主機都訪問同一個外網服務器, 那么對于服務器返回的數據中, 目的IP都是相同的. 那么NAT路由器如何判定將這個數據包轉發給哪個局域網的主機?

  • 這時候NAPT來解決這個問題了. 使IP+port來建立這個關聯關系
  • (還是 我們之前提到的,一層區分不了,那就再加一層😋
  • 當數據包回到NAT路由器的時候,目前并不能確認這個報文應該轉給主機A、B、C當中哪一個。
  • 但我們要求它必須分清楚,是誰的數據就給誰返回,就決定了當前路由器就必須自己維護從外網到內網之間數據包和主機之間的對應關系。
  • 學了這么久實際上我們知道主機A、B、C三臺主機IP地址是不一樣的,所以對應每臺主機都會有特定的標識符來告訴NAT路由器我們各自是誰。
  • 可是有一個細節我們從開始到現在一直沒說,實際上通信的并不全是客戶端A、B、C這些主機,其實本質是戶端A、B、C上特定的進程和服務器上某個特定的進程在通信,而進程都是自己的端口號的。并且同時可能會存在一臺主機上有不同進程可能都要去訪問外網。

所以NAT路由器除了要區分客戶端A、B、C之間差別,也要有能力區分同一臺主機不同的進程!

  • 說白了就是NAT路由器不僅僅要區分客戶端A、B、C,然后把響應報文要轉給不同的主機。
  • 還有同一臺主機不同進程發給其他服務器,服務器處理之后把響應報文都發到NAT路由器,NAT路由器要把響應給同一臺主機的不同進程,所以還需要端口號來區分同一臺主機不同進程!

所以數據包在經過NAT路由器進行轉發出去的時候,不僅要考慮源IP地址替換的問題,源端口號也要被替換。

因此路由器還要在自身內部維護一張NAT轉換表 其實這張轉換表是KV式的轉換表。

(于是 又回到了我們的算法問題上面

  • 公網IP肯定是不一樣的,局域網內不同主機IP地址也是不一樣的。
  • 可能是同一臺主機不同進程發送請求,也有可能是不同主機但是端口號相同的進行發送請求

但是因為有IP和端口號的存在這個組成四元組的請求在局域網內一定是唯一四元組。


(??理解:雖然客戶端發的可能是去 同一個主機+port,但因為是不同客戶端發的,我們之后可能還涉及到了一個應答的問題,所以在 nat 轉發的時候,替換為相同的 轉發的源 ip 地址時,port 端口要設置的不同

  • 把請求報文經過NAT路由器源IP地址的轉換,源port也可能轉換(可能一臺主機不同進程都訪問外網)。
  • 替換之后這個四元組請求在公網內也是唯一的。
    所以NAT路由表做了源IP替換和可能源port的替換之后變成了新的源IP和或者新的源port,因為一個是私網IP一個是公網IP,這兩種IP一定是不一樣的,也就是說替換完了之后兩個四元組的源IP一定是不一樣的
  • 就注定了這兩個唯一的四元組合起來整體一定是不一樣的并且是唯一的。

所以在NAT路由器中就構建了互為鍵值的映射表 并且都是唯一的。

也就是說從左到右,左側的值是具有唯一性的,從右到左,右側的值也是具有唯一性的。
?


所以數據包回來到NAT路由器后,雖然NAT路由器看到目的IP都是一樣的,但是曾經端口號可能做了替換,因此看到的整體一定是不一樣的。

  • 然后再根據映射,所以最終就可以區分出那個數據包是那個主機的進程的。
  • 所以不用擔心數據包回來的問題,因為路上的路由器都會建立NAT轉換表。這個NAT轉換表可以從左到右查,也可以從右到左查。(有不同的端口,可以實現來區分返回)
  • 經過剛才的分析,如果主機上從來沒有訪問外網,那外網能不能之間通過路由器訪問這臺主機呢?
    不能!因為路上的路由器并沒有建立對應的映射關系。
  • 所以也不能把數據反向的從外網推送給該主機。除非該主機訪問外網然后路上路由器記錄對應的映射關系,外網才能訪問該主機。

這種互為映射的關聯關系也是由NAT路由器自動維護的.

  • 例如在TCP的情況下, 建立連接時, 就會生成這個表項;
  • 在斷開連接后, 就會刪除這個表項
    所以有NAT這種技術的存在可以讓我們構建各自各樣的子網,然后通過轉發訪問公網
  • 只要保證最終的出口路由器(連接公網的路由器)它所面對公網的IP地址是唯一的就可以了,內網環境可以使用NAT進行各自轉發

NAT技術的缺陷

由于NAT依賴這個轉換表, 所以有諸多限制:

  • 無法從NAT外部向內部服務器建立連接; (NAT 只能從內向外)
  • 轉換表的生成和銷毀都需要額外開銷;
  • 通信過程中一旦NAT設備異常, 即使存在熱備, 所有的TCP連接也都會斷開;(這是一個很危險的事情)

2.NAT和代理服務器

代理服務器又分為正向代理和反向代理.

舉個例子

花王尿不濕是一個很經典的尿不濕品牌, 產自日本.
我自己去日本買尿不濕比較不方便, 但是可以讓我在日本工作的表姐去超市買了快遞給我. 此時超市看到的買家是我表姐, 我的表姐就是 “反向代理”;(代表的是日本超市)

就好比我自己在訪問時看不到真正服務器,我只知道要什么東西就找這個代理服務器要。這就是反向代理。

后來找我表姐買尿不濕的人太多了, 我表姐覺得天天去超市太麻煩, 干脆去超市買了一大批尿不濕屯在國內家里, 如果有人來找她代購, 就直接把屯在國內家里的貨發出去, 而不必再去超市. 此時我表姐就是 "正向代理(代表的是客戶)

代理客戶端的是 正向代理

代理服務端的是 反向代理

(相當于 這個正 是以客戶為正)

一般我們在公司層面,現在有很多機器,這些機器通過網絡訪問公司內部的服務器。

  • 公司內部一定是有多種服務器的,可是有這么多服務器都暴露在公網里面, 每一臺服務器也都得有自己公網IP的話,那么最終我們應該訪問那一臺服務器呢?其實是比較尷尬的。
  • 所以提供服務的一方呢,可能會給我們提供一個入口服務器。這個入口服務器一般會部署某些網絡服務,現在就變成了只有這一臺入口服務器有自己的公網IP,暴露在公網里,所有人都訪問這臺入口路由器,那么這一臺機器最終就可以把所有人請求轉發到它內網中某臺服務器來對外提供服務。

我們就把這臺入口機器稱之為代理服務器嚴格來說稱之為反向代理服務器

  • 假設現在有4千萬個客戶端,有大量的請求都過來的,反向代理服務器收到大量的請求,如果它內部沒有做任何處理,把請求全都給一臺機器或者少量幾臺機器
  • 最終會導致這幾臺機器壓力非常大,其他機器很閑,最終導致這個集群承受壓力能力變得非常低。
  • 所以反向代理為了解決這個問題,在自己內部中當有請求到來它內部有策略的把請求均衡的分散到整個集群所有主機上,這種策略我們稱之為負載均衡

  • 一般作為反向代理服務器配置都比較高,上面通常充當反向代理服務的一般有一些軟件服務,比如說Nginx,它是一款web服務器也可以充當代理服務器。
  • 一般把結果返回給客戶端有兩種做法,一種是把對應的處理結果返回給代理,然后由代理通過網絡轉發給客戶端。

另一種把對應的處理結果由內網機器直接通過網絡訪問客戶端。

反向代理通常作為機房入口機器,來實現分發和負載均衡

反向代理服務器在學校網絡環境中的應用

  1. 分發和負載均衡:反向代理通常作為機房或網絡入口,用于實現流量的分發和負載均衡,優化資源使用并提高訪問效率。
  2. 訪問控制與緩存:當學生嘗試通過校園網訪問外網時,實際上請求首先發送到學校的反向代理服務器。學校可以通過這道“門”限制學生的訪問,例如阻止訪問某些不被允許的內容。此外,如果多個用戶請求相同的內容(如觀看同一部電影),服務器可以緩存這些內容,并在后續請求中直接提供緩存版本,減少重復的公網訪問,提高響應速度。
  3. 禁止訪問:對于不允許訪問的公網資源,學校可以直接在反向代理服務器上丟棄這些請求,從而阻止學生訪問特定的外網內容。
  4. 上網認證與收費:為了管理校園網資源,學校可能會要求學生通過登錄頁面進行身份驗證和繳費確認后才能上網。所有網絡請求都需經過這臺服務器,確保只有通過認證且付費的用戶才能獲得公網訪問權限。這種方式不僅幫助學校管理網絡資源,還能保證用戶的身份安全和服務質量。

  • 像這種服務器替用戶去訪問我們稱之為正向代理。它可以緩存資源,然后從學校層面可以根據正向代理服務器對學生所訪問的各種資源進行限定,同理也可以對學生做入網許可的管理,這就是正向代理。正向代理服務器歸根結底其實就是把所有請求收集在一起方便對請求本身做管理。

上面內容好像和剛才說的NAT有些類似,NAT是在做由路由器替用戶去進行請求,這不就是正向代理,那么是不是這樣呢?

  • 路由器往往都具備NAT設備的功能, 通過NAT設備進行中轉, 完成子網設備和其他子網設備的通信過程.
  • 代理服務器看起來和NAT設備有一點像. 客戶端像代理服務器發送請求, 代理服務器將請求轉發給真正要請求的服務器; 服務器返回結果后, 代理服務器又把結果回傳給客戶端.
  • 看起來它們倆工作原理好像有一點像,但其他它們倆是不同的東西。

那么NAT和代理服務器的區別有哪些呢?

(即 如何理解 NAT 的轉發,和代理服務器的轉發 之間的區別

從應用上講,

  • NAT設備是網絡基礎設備之一, 解決的是IP不足的問題.
  • 代理服務器則是更貼近具體應用, 比如通過代理服務器進行翻墻, 另外像迅游這樣的加速器, 也是使用代理服務器.

從底層實現上講,

  • NAT是工作在網絡層, 直接對IP地址進行替換.
  • 代理服務器往往工作在應用層.

從使用范圍上講,

  • NAT一般在局域網的出口部署,
  • 代理服務器可以在局域網做, 也可以在廣域網做, 也可以跨網.

從部署位置上看,

  • NAT一般集成在防火墻, 路由器等硬件設備上,
  • 代理服務器則是一個軟件程序, 需要部署在服務器上.代理服務器是一種應用比較廣的技術.

  • 翻墻: 廣域網中的代理.
  • 負載均衡: 局域網中的代理.

3.網線通信各層協議總結

以下是對網絡通信各層協議的整理表格,按層級結構分類展示關鍵知識點:

協議層級

核心協議/概念

主要特點

關鍵知識點

數據鏈路層

以太網(Ethernet)

實現同一局域網內設備間的直接通信

? 包含物理層規范(拓撲結構、傳輸速率)
? 幀結構:目的MAC+源MAC+類型+數據+CRC
? MAC地址唯一標識網卡
? ARP協議實現IP到MAC的解析
? MTU限制單次傳輸最大數據量(默認1500字節)

ARP協議

動態維護IP地址與MAC地址映射關系

? 通過廣播請求獲取目標MAC
? ARP緩存表存在老化機制

網絡層

IP協議(IPv4/IPv6)

實現跨網絡的數據路由與尋址

? IP地址邏輯標識設備
? 子網劃分(CIDR無類域間路由)
? NAT解決IP短缺(私有IP轉換公網IP)
? IP分片機制應對MTU限制
? TTL防止數據包無限循環

ICMP協議

網絡狀態診斷與控制

? Ping命令基于ICMP回顯請求
? Traceroute利用TTL超時機制追蹤路徑

路由協議(如OSPF、BGP)

動態選擇最優傳輸路徑

? 路由表維護目標網絡與下一跳關系
? 路由決策基于跳數、帶寬、延遲等指標

傳輸層

TCP協議

提供可靠、面向連接的端到端傳輸

? 三次握手建立連接/四次揮手斷開
? 滑動窗口+確認應答保證可靠性
? 擁塞控制(慢啟動、擁塞避免)
? 流量控制(接收窗口動態調整)
? 粘包問題需應用層處理

UDP協議

提供高效、無連接的簡單傳輸服務

? 無連接、不可靠但延遲低
? 適用于實時音視頻傳輸
? 需應用層實現可靠性機制
? 受MTU限制需控制報文大小

應用層

HTTP/HTTPS

萬維網數據通信基礎

? 請求-響應模型(GET/POST等)
? 無狀態協議,依賴Cookie/Session
? HTTPS=HTTP+TLS加密

DNS協議

域名與IP地址的映射系統

? 分層解析(根域名→頂級→權威)
? 本地DNS緩存加速查詢
? 支持遞歸/迭代查詢模式

自定義應用協議

滿足特定業務需求

? 需明確定義報文格式(頭部+載荷)
? 約定序列化方式(JSON/Protobuf等)
? 設計重傳/去重等可靠性機制

補充說明

  1. 層級關聯
    ? 數據鏈路層MAC地址用于局域網通信 → 網絡層IP地址實現跨網尋址 → 傳輸層端口號定位具體應用 → 應用層協議處理具體業務數據
  2. 典型交互流程

  1. 協議設計原則
    ? 下層為上層提供服務(如IP層依賴數據鏈路層傳輸)
    ? 協議開銷與效率的平衡(TCP可靠性 vs UDP高效率)
    ? 安全性分層實現(鏈路層加密/WiFi WPA2、傳輸層TLS、應用層HTTPS)

4.五種 IO 模型

1.什么是IO?什么是高效的IO?

在之前我們都知道的input,output不就是IO嗎

  • 站在馮諾依曼體系角度我們知道從外設把數據搬到內存這不就是Input嗎
  • 把數據從內存拷貝到外設中這不就是output嗎。

這不就是傳說中的IO嗎。沒錯,但是這種理解還不夠深刻!

  • 當我們在網絡中發送數據的時候是使用write發生,read讀取。
  • 當我們在進行write寫入的時候曾經說過,我們在應用層調用write本質并不是把數據發送到網絡中,其實只是把數據從應用層拷貝到傳輸層的發送緩沖區,所有write本質就是拷貝。
  • 當我們調用read讀取數據時,其實并不是從網絡中讀取,而是從傳輸層的接收緩沖區中把數據從內核中拷貝到應用層,所以read也是拷貝函數。可是你想拷貝就能給你拷貝嗎?

你想write,有沒有可能發送緩沖區因為流量控制的問題發送緩沖區已經被寫滿了數據,你想write但當前緩沖區沒有空間讓你write了。

  • 那么此時write操作默認就是阻塞在哪里,直到緩沖區有空間了
  • write我們寫代碼到現在見到很少。但是當我們read讀取數據的時候,我們被阻塞的情況是非常常見的。

以讀為例,說讀取就是拷貝這句話沒錯,但是當你想拷貝就能拷貝嗎?

萬一人家接收緩沖區就沒有數據呢?你的read只能阻塞住。所以要記住read、write本質就是拷貝,但是拷貝是有條件的。


所以不用考慮操作系統,就站在read接口使用角度,調用read/recv… 有兩種情況

  1. 沒有數據,就會阻塞住
  2. 有數據,read/recv… 會在拷貝完成之后進行返回

這個阻塞不就是在等待資源就緒嗎。

所以不能簡單認為read/recv… 只有拷貝。這是不全面的認識。

read/recv… 讀取的本質應用要分成兩種東西。

  • 站在我們角度read/recv…就是input。
  • 讀取也是同樣如此要風兩種東西,write/send…就是output。

IO本質:
IO = 等 + 數據拷貝

在系統層面和網絡層面IO都叫數據拷貝,就比如寫文件的時候,把數據寫到文件的過程我們根本不知道,調用write也只是把文件寫到操作系統里,然后由操作系統把數據刷新到文件里。

  • 同理,我們也沒有資格把數據直接寫到網絡里,只是把數據交給了操作系統,由操作系統幫我們發送。
  • 所以我們發現系統和網絡在IO的處理上是一至的。
  • 在系統的時候我們不說IO=等+數據拷貝,是因為在系統層面等這個事情不直觀,訪問一個本地文件很快就寫完成,很快就讀完成了。
  • 看不到等。其實有沒有等呢?一定要等!今天就知道了,你要讀取數據,但數據可能并不在內存中,你必須要等,因為操作系統首先要把數據從外設(磁盤)搬到內存里。
  • 而磁盤是外設,所以操作系統要給磁盤下達指令把數據從磁盤中拷貝到內存等工作做完了,然后你才把數據從操作系統拷貝到用戶,只不過這個過程太快了,你感受不到。

今天就不一樣,在網絡通信距離變長了,還要流量控制、擁塞控制等,所以距離一長等的比重就顯得明顯了,就能感覺到IO=等+數據拷貝了。

什么是高效的IO?

你經常會聽別人說我們要高效的IO,憑什么?你IO高效的提高究竟是在做哪方面的提高?

  • 首先數據拷貝這件事情,它的效率是固定的。
  • 因為數據拷貝的的本質是從硬件到硬件,該花多少時間就花多少時間,要么就是由你主機上的總線的位寬決定的,要么就是由你網絡的帶寬決定的。
  • 所以這個東西本身就是確定的,只要你能保證你在拷貝的時候它在100%一直在拷貝,它的效率就已經到達上限了。

既然IO = 等 + 數據拷貝,那什么叫做高效IO呢?
其實,只要減少 等待 的比重,即可!

  • 想象一下調用read只花1秒,可是其中有99%的時間都在等待,等待的事件永遠是主要矛盾,那么只有1%的時間花在拷貝上,拷貝本身就是從操作系統拷貝到用戶,它是從內核到用戶。
  • 站在硬件角度上就是從內存到內存,這個時間本身就是一個固定時間,站在操作系統角度把數據從外設搬到內存,把硬件上速度拉滿它能拷貝多少就是多少。
  • 可是在IO大部分時間在等,如果把等和數據拷貝時間反過了,99%在拷貝,1%在等
  • 我調用read很快就能夠或者等的比重降的非常低,一調用read就直接返回,那這就叫做高效IO。

而在 等待 這件事情上,我們是需要從軟件策略完成的。
read/recv它們策略很簡單粗暴,沒有數據就等,有數據就拷貝。

2.有那些IO的方式?這么多的方式,有那些是高效的?

下面講個小故事理解IO的過程。
我們可能見過別人釣魚或者自己釣魚,那么把釣魚步驟化繁為簡,釣魚分兩步
釣魚 = 等 + 釣

釣魚:

  1. 張三:專注死盯魚漂,不達目的不罷休 → 阻塞IO
  2. 李四:三心二意,頻繁查看魚漂 → 非阻塞IO
  3. 王五:掛鈴鐺通知,輕松做其他事 → 信號驅動IO
  4. 趙六:百竿齊發,來回巡檢 → 多路復用(select/epoll)
  5. 田七:完全委托小王,自己專注工作 → 異步IO

效率分析:

  • 直觀效率:趙六 > 王五 > 張三 > 李四 > 田七(但田七實現了零等待)
  • 理論極限:田七的異步模式效率最高(系統代為完成所有操作)
  • 現實折中:趙六的多路復用是性價比最高的方案

關鍵對應關系:

| 故事元素      | 計算機概念            | 性能瓶頸             |
|---------------|-----------------------|----------------------|
| 魚漂動靜      | 數據就緒事件          | 事件檢測延遲         |
| 100根魚竿     | 多文件描述符          | 系統監控上限         |
| 來回巡檢      | select輪詢            | O(n)時間復雜度       |
| 鈴鐺響動      | SIGIO信號             | 信號處理延遲         |
| 小王代勞      | aio_read異步調用      | 系統回調機制         | 

現實工程啟示:

  1. 阻塞IO:簡單但浪費線程資源(如傳統socket編程)
  2. 非阻塞IO:CPU空轉嚴重(需配合超時機制)
  3. 信號驅動:適用于低頻事件(如串口通信)
  4. 多路復用:高并發基石(nginx/epoll模型)(可以一次等待多個)
  5. 異步IO:未來方向但實現復雜(如Windows IOCP)

💡 在Linux中,epoll_wait就是趙六的"巡檢優化版",用紅黑樹管理魚竿(文件描述符),事件通知復雜度降為O(1)

所以,釣魚的人,等的比重比較低,單位時間,釣魚的效率就高!

  • 其次,張三,李四,王五,趙六,田七(小王)誰釣魚效率最高?
  • 首先張三、李四、王五、田七(小王)它們只有一人一竿,只有趙六是一人多竿。魚竿多就是了不起。假設趙六100條竿,加上其他的人4條竿。
  • 站在魚的角度頭頂上有著104個誘餌,咬到任何一個誘餌概率是一樣的,要是咬的話,趙六釣魚成功概率就是100/104,其他人只是1/104,所以趙六釣魚時任一魚竿就緒概率概率就100/104。
  • 所以單位時間內任何一個魚竿就緒概率就是比其他人大。所以站在旁觀者看趙六就可能一直有魚咬竿的事情。
  • 所以單位時間內,趙六這種釣魚方式等的比重比較低,所以趙六釣魚的效率比較高

我們把這種一次可以等待多個魚竿的釣魚方式叫做多路轉接/多路復用

張三 ------> 阻塞IO
李四 ------> 非阻塞IO
王五 ------> 信號驅動式IO(還沒有釣魚就知道鈴鐺響了,魚就咬鉤了)
趙六 ------> 多路轉接/多路復用
田七 (小王) ------> 異步IO

  • 張三、李四,王五、趙六、田七 ----> 進程/線程
    小王 ----> OS
    魚 ----> 數據
    河 ----> 內核空間
    魚鰾 ----> 數據就緒的事件
    魚竿 ----> 文件描述符
    釣魚的動作 ----> read/recv…釣魚

理解:

  • 當張三這個進程去讀數據時,只要底層數據沒有就緒,就要一直等待將自己掛起。只有數據就緒了,才會被喚醒然后讀到數據在返回。
  • 李四這個進程去讀數據時,當底層數據沒有就緒,李四并不會因為read/recv…而被阻塞,而是立馬返回,在自己的while循環中去做其他事情。然后再去讀(可以設定詢問間隔時間)。
  • 王五這個進程在進行IO之前,一旦IO了操作系統會給進程推送SIGIO信號(需要特定接口去設置),王五在進行調用recv之前,他只是注冊一下SIGIO的方法,然后王五繼續向后執行做自己的事情,一旦有IO就緒了,王五的信號捕捉方法里直接調用recv,然后把數據從內核拷貝到用戶空間,這叫做信號驅動。
  • 趙六這個進程拿著多個文件描述符,一次等待多個,具體怎么等后面說。
  • 田七這個進程,通過異步IO的接口直接將數據讀取的工作交給操作系統,除了把任務交給操作系統同時他還給了操作系統一個緩沖區(魚桶),以及給了操作系統一個通知(電話),比如是某些回調方法或者某些回調策略。
  • 讓操作系統在讀取數據時直接把數據全部從內核中讀取到緩沖區,然后用告訴操作系統的方法,來告知田七數據準備好了讓田七直接用就好了,這就叫做異步IO。

所以我們把上面對IO的方式,我們稱之為五種IO模型。所有IO都隸屬于上面模型,目前大部分使用的文件接口用的是阻塞IO

多路轉接/多路復用是比較高效的


對比五種IO模型的差別

張三、李四、王五在效率上有差別嗎?

沒有因為他們在整個IO過程,該等多少時間就等了多少時間。效率上是沒有差別的。都只有一個魚竿,而魚釣上來的概率是一樣的。
但是在其他方面有差別!阻塞式什么事都不干,只進行IO,所以其他方面沒有優勢。

  • 而非阻塞式IO,它可以輪詢式的方法檢測底層數據是否就緒,在檢測沒有數據就緒時還可以在等的時間做其他事情。
  • 信號驅動也是一樣的,在等待數據就緒時,也同樣在等的時間做其他事情。
  • 所以張三、李四、王五在IO上效率是一樣的,但是整體上李四,王五可以做其他事情,表現上他們好像多做了事情然后更高效一點,但是這高效沒有體現在IO上。

王五(信號驅動)究竟有沒有等待呢?

他一定等了,要不然王五早就走了,為什么還要待在岸邊呢?所以本質上還是等了。

只不過等的方式有些差別,別人是主動去檢測,而他變成了你好了,你來叫我。信號驅動是采用回調的方式來進行等待的。

  • 張三、李四、王五、趙六他們其實每一個人都等了,當魚咬鉤時每一個人都釣了。每一個人都參與了IO的過程,我們把他們都可以稱之為同步IO
  • 田七并沒有等魚咬鉤,也沒有當魚咬鉤時把魚釣上來,他連河邊都沒有去過,他把任務交給小王,并沒有參與IO的兩個階段中的任何一個階段,我們把他稱之為異步IO
  • (他都沒有進行 IO,直接拿到了結果,我們之前寫的 rpc 就是一個異步 IO,但是謹記,沒有銀彈異步有時容易造成混亂,所以我們有時會采用協程)

阻塞式IO和非阻塞式IO有什么差別呢?
共同點:釣
不同點:等的方式不同!

異步這里好理解,但是同步這里就有一個問題了,我們曾經學過一個線程同步的概念。

  • 現在又學了一個同步IO那這兩個同步是一樣的嗎?
    它們之間的關系就和老婆和老婆餅一樣,沒有任何關系!當我們在網絡中搜索同步的概念時一定要加前提條件。線程同步是讓多線程執行具有一定的順序性。還是說IO的同步允許參與IO的過程!

為什么多路轉接/多路復用是高效的代名詞?
因為 IO = 等 + 數據拷貝,多路轉接/多路復用可以減少等的比重

同樣等,但是一次可以等待多個文件描述符至少有一個就緒。調用read等的比重降低了,未來效率就高了。


異步 IO

異步I/O的一個缺點是在某些情況下可能會導致更多的上下文切換和更高的開銷,因為操作系統需要頻繁地在多個任務之間進行調度。

用之前釣魚故事中的「田七委托小王」場景來解釋異步IO的缺點:

🎣 關鍵缺陷類比

田七(應用程序)           小王(操作系統)│                          ││ 委托釣魚任務              ││─────────────────────────>││                          ├─ 需要準備魚竿、魚餌、水桶...│                          ├─ 必須完全信任小王的釣魚能力│                          ├─ 無法實時查看釣魚進度│                          │(突然下暴雨也不知道)│                          ││   ←─── 桶滿才通知 ────    │

📝 具體技術缺陷

  1. 開發復雜度劇增
    • 需要設計復雜的回調機制(如同田七要給小王寫詳細釣魚指南)
    • 狀態管理困難(無法直觀看到魚竿的實時狀態)
    • 示例代碼復雜度對比:
// 同步模式(張三式)
fish = wait_and_catch(); // 簡單直觀// 異步模式(田七式)
start_async_catch(callback_func); 
while(1){ /* 處理其他事但需維護回調狀態 */ }
  1. 系統支持碎片化

操作系統

實現方式

如同...

Linux

libaio/epoll

小王只會傳統釣魚法

Windows

IOCP

小王會用智能釣魚機器人

macOS

kqueue

小王擅長海釣

  1. 調試噩夢
    • 回調鏈斷裂時難以追溯(如小王釣到魚但忘記打電話)
    • 多線程+異步的競態條件(多個小王同時操作魚桶)
  1. 資源隱性消耗
    • 每個異步操作需要維護上下文(如同每個魚竿要配記錄本)
    • 事件循環本身消耗CPU(田七頻繁看手機是否收到通知)
    • 所以他哪怕去干別的事了,只等結果,但是他等的也不安心..(異步IO? 存在的問題)
  1. 不適用場景
    ┌───────────────┬───────────────┐
    │ 適合場景 │ 如同... │
    ├───────────────┼───────────────┤
    大規模并發請求 │ 趙六式百竿監控 │(多路復用)
    ├───────────────┼───────────────┤
    │ 簡單串行任務 │ 張三式專注單竿 │
    └───────────────┴───────────────┘

?? 實踐中的坑

  • 緩沖區管理失控:如同小王釣的魚太多,桶溢出導致魚逃跑(內存泄漏)
  • 超時機制缺失:若小王永遠釣不滿桶,田七會永久等待(死鎖)
  • 優先級反轉:緊急釣魚需求可能被普通請求阻塞

建議在需要處理 10,000+ 并發連接 的場景(如高頻交易系統)才考慮純異步方案,其他情況可結合多路復用(趙六模式)+線程池優化。

下篇文章我們將繼續詳細講解代碼實現~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/79479.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/79479.shtml
英文地址,請注明出處:http://en.pswp.cn/web/79479.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Unity基礎學習(八)時間相關內容Time

眾所周知,每一個游戲都會有自己的時間。這個時間可以是內部,從游戲開始的時間,也可以是外部真實的物理時間,時間相關內容 主要用于游戲中 參與位移計時 時間暫停等。那么我們今天就來看看Unity中和時間相關的內容。 Unity時間功能…

Java游戲服務器開發流水賬(1)游戲服務器的架構淺析

新項目立項停滯,頭大。近期讀老項目代碼看到Java,筆記記錄一下。 為什么要做服務器的架構 游戲服務器架構設計具有多方面的重要意義,它直接關系到游戲的性能、可擴展性、穩定性以及用戶體驗等關鍵因素 確保游戲的流暢運行 優化數據處理&a…

計算機視覺與深度學習 | 基于Transformer的低照度圖像增強技術

基于Transformer的低照度圖像增強技術通過結合Transformer的全局建模能力和傳統圖像增強理論(如Retinex),在保留顏色信息、抑制噪聲和平衡亮度方面展現出顯著優勢。以下是其核心原理、關鍵公式及典型代碼實現: 一、原理分析 1. 全局依賴建模與局部特征融合 Transformer的核…

Linux 文件目錄管理常用命令

pwd 顯示當前絕對路徑 cd 切換目錄 指令備注cd -回退cd …返回上一層cd ~切換到用戶主目錄 ls 列出目錄的內容 指令備注ls -a顯示當前目錄中的所有文件和目錄,包括隱藏文件ls -l以長格式顯示當前目錄中的文件和目錄ls -hl以人類可讀的方式顯示當前目錄中的文…

【Linux 系統調試】性能分析工具perf使用與調試方法

目錄 一、perf基本概念 1?. 事件類型? 2?. 低開銷高精度 3?. 工具定位? 二、安裝與基礎配置 1. 安裝方法 2. 啟用符號調試 三、perf工作原理 1. 數據采集機制 2. 硬件事件轉化流程 四、perf應用場景 1. 系統瓶頸定位 2. 鎖競爭優化 3. 緩存優化 五、perf高級…

嵌入式中屏幕的通信方式

LCD屏通信方式詳解 LCD屏(液晶顯示屏)的通信方式直接影響其數據傳輸效率、顯示刷新速度及硬件設計復雜度。根據應用場景和需求,LCD屏的通信方式主要分為以下三類,每種方式在協議類型、數據速率、硬件成本及適用場景上存在顯著差異…

【el-admin】el-admin關聯數據字典

數據字典使用 一、新增數據字典1、新增【圖書狀態】和【圖書類型】數據字典2、編輯字典值 二、代碼生成配置1、表單設置2、關聯字典3、驗證關聯數據字典 三、查詢操作1、模糊查詢2、按類別查詢(下拉框) 四、數據校驗 一、新增數據字典 1、新增【圖書狀態…

【Spring】Spring MVC筆記

文章目錄 一、SpringMVC簡介1、什么是MVC2、什么是SpringMVC3、SpringMVC的特點 二、HelloWorld1、開發環境2、創建maven工程a>添加web模塊b>打包方式:warc>引入依賴 3、配置web.xmla>默認配置方式b>擴展配置方式 4、創建請求控制器5、創建springMVC…

如何在大型項目中解決 VsCode 語言服務器崩潰的問題

在大型C/C項目中,VS Code的語言服務器(如C/C擴展)可能因內存不足或配置不當頻繁崩潰。本文結合系統資源分析與實戰技巧,提供一套完整的解決方案。 一、問題根源診斷 1.1 內存瓶頸分析 通過top命令查看系統資源使用情況&#xff…

LeetCode百題刷002摩爾投票法

遇到的問題都有解決的方案,希望我的博客可以為你提供一些幫助 圖片源自leetcode 題目:169. 多數元素 - 力扣(LeetCode) 一、排序法 題目要求需要找到多數值(元素個數>n/2)并返回這個值。一般會想到先…

Android Studio Gradle 中 只顯示 Tasks 中沒有 build 選項解決辦法

一、問題描述 想把項目中某一個模塊的代碼單獨打包成 aar ,之前是點擊 AndroidStudio 右側的 Gradle 選項,然后再點擊需要打包的模塊找到 build 進行打包,但是卻發現沒有 build 選項。 二、解決辦法 1、設置中勾選 Configure all Gradle tasks… 選項 …

深入淺出之STL源碼分析2_stl與標準庫,編譯器的關系

引言 在第一篇博客中,深入淺出之STL源碼分析1_vector基本操作-CSDN博客 我們將引出下面的幾個問題 1.剛才我提到了我的編譯器版本是g 11.4.0,而我們要講解的是STL(標準模板庫),那么二者之間的關系是什么?…

(十二)深入了解AVFoundation-采集:人臉識別與元數據處理

(一)深入了解AVFoundation:框架概述與核心模塊解析-CSDN博客 (二) 深入了解AVFoundation - 播放:AVFoundation 播放基礎入門-CSDN博客 (三)深入了解AVFoundation-播放&#xff1…

Kafka 與 RabbitMQ、RocketMQ 有何不同?

一、不同的誕生背景,塑造了不同的“性格” 名稱 背景與目標 產品定位 Kafka 為了解決 LinkedIn 的日志收集瓶頸,強調吞吐與持久化 更像一個“可持久化的分布式日志系統” RabbitMQ 出自金融通信協議 AMQP 的實現,強調協議標準與廣泛適…

配置 Web 服務器練習

一、要求 1.通過https://ip 可以訪問到網站首頁 2.通過 https://ip/private/ 實現用戶訪問控制,僅允許已經添加的 tom,jerry 能夠訪問到 private 子路徑的界面 3.通過 https://ip/vrit/ 實現能夠訪問到將系統 /nginx/virt 目錄下的網頁文件&#xff0…

MySQL索引詳解(下)(SQL性能分析,索引使用)

索引是MySQL性能優化的核心,但如何精準分析查詢瓶頸、合理設計索引,是開發者必須掌握的技能。本文結合實戰案例,系統講解SQL性能分析工具鏈與索引使用技巧,幫助讀者構建高性能數據庫系統。 一、SQL性能分析:從宏觀到微…

招行數字金融挑戰賽數據賽道賽題一

賽題描述:根據提供的用戶行為數據,選手需要分析用戶行為特征與廣告內容的匹配關系,準確預測用戶對測試集廣告的點擊情況,通過AUC計算得分。 得分0.6120,排名60。 嘗試了很多模型都沒有能夠提升效果,好奇大…

ORB-SLAM3和VINS-MONO的對比

直接給總結,整體上orbslam3(僅考慮帶imu)在初始化階段是松耦合,localmap和全局地圖優化是緊耦合。而vins mono則是全程緊耦合。然后兩者最大的區別就在于vins mono其實沒有對地圖點進行優化,為了輕量化,它一…

安裝typescript時,npm install -g typescript報錯

刪除C:\Users\用戶\下的.npmrc文件,如果你的沒有,看是不是因為將隱藏的項目勾選上了,然后去掉勾選。 重新輸入

[GESP202503 四級] 二階矩陣c++

題目描述 小 A 有一個 n 行 m 列的矩陣 A。 小 A 認為一個 22 的矩陣 D 是好的,當且僅當 。其中 表示矩陣 D 的第 i 行第 j 列的元素。 小 A 想知道 A 中有多少個好的子矩陣。 輸入 第一行,兩個正整數 n,m。 接下來 n 行,每行 m 個整數…