日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

网络相关面试题(持续更新)

發布時間:2024/3/26 70 豆豆
生活随笔 收集整理的這篇文章主要介紹了 网络相关面试题(持续更新) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.瀏覽器輸入www.baidu.com回車,會發生什么?

dns過程+路由器和交換機+操作系統網絡協議棧處理+web服務業務邏輯處理

1.域名解析成IP

每個主機在網絡中都是IP為標識的,IP才是主機在網絡中的位置,域名只是為了方便用戶記憶而已,這就要求瀏覽器能夠識別域名并且將其轉化為對應的IP地址

所以瀏覽器會有一個DNS緩存,其中記錄了一些域名與IP的對應關系,供瀏覽器快速查找需要的IP。但是這個DNS緩存不可能存下所有的域名-IP地址,何況IP地址有時候還會變化,因此當在瀏覽器DNS緩存中沒有找到的時候,就要先向DNS服務器請求域名解析,DNS域名解析時用的是UDP協議。

①客戶端從瀏覽器中輸入www.baidu.com網站網址后回車,首先瀏覽器會查詢瀏覽器本身的DNS緩存,一般只有幾分鐘的緩存,找到了就返回域名對應的IP;如果找不到,系統就會查詢本地hosts文件和本地DNS緩存信息,如果找到了,就返回域名對應IP;

②如果沒有找到對應的域名解析記錄,那么那么系統會把瀏覽器的解析請求,交給客戶端本地設置的DNS服務器地址解析(稱為Local DNS,LDNS),如果LDNS服務的本地緩存有對應的解析記錄,就會直接返回IP地址;

③如果沒有,LDNS會負責繼續請求其他DNS服務器;此時就是外網的DNS服務器了,先是根域名服務器,根據瀏覽器得到的域名,根域名服務器看到.com,會返回.com的頂級域名服務器的ip給LDNS;然后LDNS通過頂級域名服務器的ip,找到了頂級域名服務器,.com頂級域名服務器看到了是找baidu.com一級域名服務器,就將其服務器的ip返回給LDNS;然后一層一層往下找,直到找到了www.baidu.com的DNS記錄,并得到對應的IP地址,這時候LDNS會把找到的www.baidu.com的ip發送給客戶端瀏覽器,并記錄在緩存中,以便未來再次訪問。

④客戶端瀏覽器收到ip之后,就可以通過ip地址找到對應的web服務器了,即服務端主機;接下來就是三次握手建立連接了

2.與目的主機進行TCP連接(三次握手)

得到域名對應的ip地址后,也就表示可以將數據送達到目的主機了,即可以向服務器發送http請求了,但是http是應用層協議,tcp是傳輸層,所以發送http請求之前,開始我們常說的三次握手。Http請求是使用TCP進行傳輸的,可以保證可靠傳輸,并且有序,需要建立連接,才能進行數據傳輸。

3.發送和接收數據

建立連接之后,就可以發送數據了,即發送http請求
以get方法為例:

①瀏覽器向服務器發送get方法報文

②該get方法報文通過tcp-》ip-》mac-》網關-》目的主機

③目的主機收到數據幀,通過ip-tcp-http,http協議單元回應http協議格式封裝好的HTML形式數據;

④該HTML數據通過tcp-》ip-》mac-》網關-》我的主機

⑤我的主機收到數據幀,通過ip-tcp-http-瀏覽器,以網頁形式顯式HTML

4.與目的主機斷開TCP連接(四次揮手)
數據傳輸結束之后需要斷開連接,與建立連接不同,斷開連接需要多一次手,四次揮手

2. tcp三次握手,四次揮手的過程?

三次握手

1.客戶端的協議棧向服務器端發送了 SYN 包,并告訴服務器端當前發送序列號 j,客戶端進入 SYNC_SENT 狀態;

2.服務器端的協議棧收到這個包之后,和客戶端進行 ACK 應答,應答的值為 j+1,表示對 SYN 包 j 的確認,同時服務器也發送一個 SYN 包,告訴客戶端當前我的發送序列號為 k,服務器端進入 SYNC_RCVD 狀態;

3.客戶端協議棧收到 ACK 之后,使得應用程序從 connect 調用返回,表示客戶端到服務器端的單向連接建立成功,客戶端的狀態為 ESTABLISHED,同時客戶端協議棧也會對服務器端的 SYN 包進行應答,應答數據為 k+1;

4.應答包到達服務器端后,服務器端協議棧使得 accept 阻塞調用返回,這個時候服務器端到客戶端的單向連接也建立成功,服務器端也進入 ESTABLISHED 狀態。

四次揮手的過程:

1.首先,一方應用程序調用 close,我們稱該方為主動關閉方,該端的 TCP 發送一個 FIN 包,表示需要關閉連接。之后主動關閉方進入 FIN_WAIT_1 狀態

2.接著,接收到這個 FIN 包的對端執行被動關閉。這個 FIN 由 TCP 協議棧處理,我們知道,TCP 協議棧為 FIN 包插入一個文件結束符 EOF 到接收緩沖區中,應用程序可以通過 read 調用來感知這個 FIN 包。一定要注意,這個 EOF 會被放在已排隊等候的其他已接收的數據之后,這就意味著接收端應用程序需要處理這種異常情況,因為 EOF 表示在該連接上再無額外數據到達。此時,被動關閉方進入 CLOSE_WAIT 狀態。

3.接下來,被動關閉方將讀到這個 EOF,于是,應用程序也調用 close 關閉它的套接字,這導致它的 TCP 也發送一個 FIN 包。這樣,被動關閉方將進入 LAST_ACK 狀態。

4.最終,主動關閉方接收到對方的 FIN 包,并確認這個 FIN 包。主動關閉方進入 TIME_WAIT 狀態,而接收到 ACK 的被動關閉方則進入 CLOSED 狀態。進過 2MSL 時間之后,主動關閉方也進入 CLOSED 狀態。

"每個方向都需要一個 FIN 和一個 ACK,因此通常被稱為四次揮手"

3.為什么連接的時候是三次握手,關閉的時候卻是四次握手?為什么不能用兩次握手進行連接?

為了實現可靠數據傳輸,TCP 協議的通信雙?,都必須維護?個序列號. 以標識發送出去的數據包中,哪些是已經被對?收到的。 三次握?的過程即是通信雙?相互告知序列號起始值,并確認對?已經收到了序列號起始值的必經步驟。 "如果只是兩次握?, ?多只有連接發起?的起始序列號能被確認, 另??選擇的序列號則得不到確 認。"

4.為什么TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?

"只有發起連接終止的一方會進入 TIME_WAIT 狀態。"

1.TIME_WAIT 的作用

1.首先,這樣做是為了確保最后的 ACK 能讓被動關閉方接收,從而幫助其正常關閉。 TCP 在設計的時候,做了充分的容錯性設計,比如,TCP 假設報文會出錯,需要重傳. 在這里,如果圖中主機 1 的 ACK 報文沒有傳輸成功,那么主機 2 就會重新發送 FIN 報文。如果主機 1 沒有維護 TIME_WAIT 狀態,而直接進入 CLOSED 狀態。 它就失去了當前狀態的上下文,只能回復一個 RST 操作,從而導致被動關閉方出現錯誤現在主機 1 知道自己處于 TIME_WAIT 的狀態,就可以在接收到 FIN 報文之后,重新發出一個 ACK 報文, 使得主機 2 可以進入正常的 CLOSED 狀態。 2.第二個理由和連接“化身”和報文迷走有關系,為了讓舊連接的重復分節在網絡中自然消失。 在網絡中,經常會發生報文經過一段時間才能到達目的地的情況. 產生的原因是多種多樣的;"如路由器重啟,鏈路突然出現故障等。" 如果迷走報文到達時,發現 TCP 連接四元組(源 IP,源端口,目的 IP,目的端口)所代表的連接不復存在,那么很簡單,這個報文自然丟棄。"考慮這樣一個場景": 在原連接中斷后,又重新創建了一個原連接的“**化身**”,說是化身其實是因為這個連接和原先的連接四元組完全相同,如果迷失報文經過一段時間也到達,那么這個報文會被誤認為是連接“化身”的一個 TCP 分節,這樣就會對 TCP 通信產生影響。

所以,TCP 就設計出了這么一個機制,經過 2MSL 這個時間,足以讓兩個方向上的分組都被丟棄, 使得原來連接的分組在網絡中都自然消失,再出現的分組一定都是新化身所產生的。劃重點,"2MSL 的時間是從主機 1 接收到 FIN 后發送 ACK 開始計時的" 如果在 TIME_WAIT 時間內,因為主機1的 ACK 沒有傳輸到主機 2, 主機 1 又接收到了主機 2 重發的 FIN 報文,那么 2MSL 時間將重新計時.因為2MSL 的時間,目的是為了讓舊連接的所有報文都能自然消亡, 現在主機1重新發送了 ACK 報文,自然需要重新計時,以便防止這個ACK 報文對新可能的連接化身造成干擾。

5.如果已經建立了tcp連接,但是客戶端突然出現故障了怎么辦?

TCP 協議有一個保活機制。 這個機制的原理是這樣的:

定義?個時間段,在這個時間段內,如果沒有任何連接相關的活動,TCP 保活機制會開始作?,每隔?個時間間隔,發送?個探測報?,該探測報?包含的數據?常少,如果連續?個探測報?都沒有得到響應,則認為當前的TCP 連接已經死亡,系統內核將錯誤信息通知給上層應?程序。

在 Linux 內核可以有對應的參數可以設置保活時間保活探測的次數保活探測的時間間隔,以下都為默認值:

net.ipv4.tcp_keepalive_time=7200 net.ipv4.tcp_keepalive_intvl=75 net.ipv4.tcp_keepalive_probes=9

tcp_keepalive_time=7200:表示保活時間是 7200 秒(2?時),也就 2 ?時內如果沒有任何連接相關的活動,則會啟動保活機制

tcp_keepalive_intvl=75:表示每次檢測間隔 75 秒;

tcp_keepalive_probes=9:表示檢測 9 次?響應,認為對?是不可達的,從?中斷本次的連接
也就是說在 Linux 系統中,最少需要經過 2 ?時 11 分 15 秒才可以發現?個「死亡」連接。

這個時間是有點?的,我們也可以根據實際的需求,對以上的保活相關的參數進?設置。

如果開啟了 TCP 保活,需要考慮以下幾種情況:
第?種,對端程序是正常?作的。 當 TCP 保活的探測報?發送給對端, 對端會正常響應,這樣 TCP 保活時間會被重置,等待下?個 TCP 保活時間的到來。

第?種,對端程序崩潰并重啟。 當 TCP 保活的探測報?發送給對端后,對端是可以響應的,但由于沒有該連接的有效信息,會產??個 RST 報?,這樣很快就會發現 TCP 連接已經被重置。

第三種,是對端程序崩潰,或對端由于其他原因導致報?不可達。 當 TCP 保活的探測報?發送給對端后,?沉?海,沒有響應,連續幾次,達到保活探測次數后,TCP 會報告該 TCP 連接已經死亡。

6.如果服務器上存在大量 CLOSE_WAIT 情況,如何處理?

close_wait是被動關閉連接是形成的,根據TCP狀態機,服務器端收到客戶端發送的FIN,TCP協議棧會自動發送ACK,鏈接進入close_wait狀態。

但如果服務器端不執行socket的close()操作,狀態就不能由close_wait遷移到last_ack,則系統中會存在很多close_wait狀態的連接,如下圖所示:

可能得原因如下:
1.關閉socket不及時:例如I/O線程被意外阻塞,或者I/O線程執行的用戶自定義Task比例過高,導致I/O操作處理不及時,鏈路不能被及時釋放。

通常,CLOSE_WAIT 狀態在服務器停留時間很短,如果你發現大量的 CLOSE_WAIT 狀態,那么就意味著被動關閉的一方沒有及時發出 FIN 包,一般有如下幾種可能

1.程序問題:如果代碼層面忘記了 close 相應的 socket 連接,那么自然不會發出 FIN 包,從而導致 CLOSE_WAIT 累積;或者代碼不嚴謹,出現死循環之類的問題,導致即便后面寫了 close 也永遠執行不到。

2.響應太慢或者超時設置過小:如果連接雙方不和諧,一方不耐煩直接 timeout,另一方卻還在忙于耗時邏輯,就會導致 close 被延后。響應太慢是首要問題,不過換個角度看,也可能是 timeout 設置過小。

7.如果服務器上存在大量 TIME_WAIT 情況,如何改善?

過多的 TIME_WAIT 的主要危害有兩種:

第一是內存資源占用,這個目前看來不是太嚴重,基本可以忽略。

第二是對端口資源的占用,一個 TCP 連接至少消耗一個本地端口。要知道,端口資源也是有限的,一般可以開啟的端口為 32768~61000 ,也可以通過net.ipv4.ip_local_port_range指定,如果 TIME_WAIT 狀態過多,會導致無法創建新連接

如何優化 TIME_WAIT?

1.net.ipv4.tcp_max_tw_buckets
一個暴力的方法是通過 sysctl 命令,將系統值調小。這個值默認為 18000,當系統中處于 TIME_WAIT 的連接一旦超過這個值時,系統就會將所有的 TIME_WAIT 連接狀態重置,并且只打印出警告信息。這個方法過于暴力,而且治標不治本,帶來的問題遠比解決的問題多,不推薦使用。

2.調低 TCP_TIMEWAIT_LEN,重新編譯系統
這個方法是一個不錯的方法,缺點是需要“一點”內核方面的知識,能夠重新編譯內核。我想這個不是大多數人能接受的方式。

3.SO_LINGER 的設置
英文單詞“linger”的意思為停留,我們可以通過設置套接字選項,來設置調用 close 或者 shutdown 關閉連接時的行為。

int setsockopt(int sockfd, int level, int optname, const void *optval,socklen_t optlen); struct linger {int  l_onoff;    /* 0=off, nonzero=on */int  l_linger;    /* linger time, POSIX specifies units as seconds */ }

設置 linger 參數有幾種可能:

1.如果l_onoff為 0,那么關閉本選項。l_linger的值被忽略,這對應了默認行為,close 或 shutdown 立即返回。如果在套接字發送緩沖區中有數據殘留,系統會將試著把這些數據發送出去。

2.如果l_onoff為非 0, 且l_linger值也為 0,那么調用 close 后,會立該發送一個 RST 標志給對端,該 TCP 連接將跳過四次揮手,也就跳過了 TIME_WAIT 狀態,直接關閉。這種關閉的方式稱為“強行關閉”。 在這種情況下,排隊數據不會被發送,被動關閉方也不知道對端已經徹底斷開。只有當被動關閉方正阻塞在recv()調用上時,接受到 RST 時,會立刻得到一個“connet reset by peer”的異常。

struct linger so_linger; so_linger.l_onoff = 1; so_linger.l_linger = 0; setsockopt(s,SOL_SOCKET,SO_LINGER, &so_linger,sizeof(so_linger));

3.如果l_onoff為非 0, 且l_linger的值也非 0,那么調用 close 后,調用 close 的線程就將阻塞,直到數據被發送出去,或者設置的l_linger計時時間到。

8.tcp和udp對比有什么區別?分別用在哪些場景?舉例說明

1.TCP?向連接(如打電話要先撥號建?連接); UDP是?連接的,即發送數據之前不需要建?連接。 2.TCP提供可靠的服務,通過TCP連接傳送的數據,?差錯,不丟失,不重復,且按序到達; UDP盡最?努?交付,即不保證可靠交付。 3.Tcp通過校驗和,重傳控制,序號標識,滑動窗?、確認應答實現可靠傳輸。 如丟包時的重發控 制,還可以對次序亂掉的分包進?順序控制。 4.UDP具有較好的實時性,?作效率?TCP?,適?于對?速傳輸和實時性有較?的通信或?播通信。 5.每?條TCP連接只能是點到點的;UDP?持?對?,?對多,多對?和多對多的交互通信。 5.TCP對系統資源要求較多,UDP對系統資源要求較少。

TCP 場景

1.遠程控制(SSH) 2.File Transfer Protocol(FTP) 3.郵件(SMTP、IMAP)等 4.點對點文件傳出(微信等)

UDP 場景

1.網絡游戲 2.音視頻傳輸 3.DNS 4.Ping 5.直播

模糊地帶(TCP、UDP 都可以考慮)

1.HTTP(目前以 TCP 為主) 2.文件傳輸

總結
1.UDP 的核心價值是靈活、輕量,構造了最小版本的傳輸層協議。
2.TCP 最核心的價值就是提供封裝好的一套解決可靠性的優秀方案

TCP 幫助我們在確保吞吐量、延遲、丟包率的基礎上,保證可靠性。 UDP 則不同,UDP 提供了最小版的實現,只支持Checksum。UDP 最核心的價值是靈活、輕量、傳輸速度快。

9.描述擁塞 控制的過程?

TCP 的擁塞控制就是在不堵塞,不丟包的情況下,盡量發揮帶寬,TCP 的擁塞控制主要來避免兩種現象,包丟失和超時重傳

水管有粗細,網絡有帶寬,也即每秒鐘能夠發送多少數據;水管有長度,端到端有時延。在理想狀態下,水管里面水的量 = 水管粗細 x 水管長度。對于到網絡上,通道的容量 = 帶寬 × 往返延遲

如果我們設置發送窗口,使得發送但未確認的包為為通道的容量,就能夠撐滿整個管道。

如圖所示,假設往返時間為 8s,去 4s,回 4s,每秒發送一個包,每個包 1024byte。已經過去了 8s,則 8 個包都發出去了,其中前 4 個包已經到達接收端,但是 ACK 還沒有返回,不能算發送成功。5-8 后四個包還在路上,還沒被接收。這個時候,整個管道正好撐滿,在發送端,已發送未確認的為 8 個包,正好等于帶寬,也即每秒發送 1 個包,乘以來回時間 8s。

如果我們在這個基礎上再調大窗口,使得單位時間內更多的包可以發送,會出現什么現象呢?

我們來想,原來發送一個包,從一端到達另一端,假設一共經過四個設備,每個設備處理一個包時間耗費 1s,所以到達另一端需要耗費 4s,如果發送的更加快速,則單位時間內,會有更多的包到達這些中間設備,這些設備還是只能每秒處理一個包的話,多出來的包就會被丟棄,這是我們不想看到的。

這個時候,我們可以想其他的辦法,例如這個四個設備本來每秒處理一個包,但是我們在這些設備上加緩存,處理不過來的在隊列里面排著,這樣包就不會丟失,但是缺點是會增加時延,這個緩存的包,4s 肯定到達不了接收端了,如果時延達到一定程度,就會超時重傳,也是我們不想看到的。

于是 TCP 的擁塞控制主要來避免兩種現象,包丟失超時重傳。一旦出現了這些現象就說明,發送速度太快了,要慢一點。但是一開始我怎么知道速度多快呢,我怎么知道應該把窗口調整到多大呢?

(1)慢啟動
如果我們通過漏斗往瓶子里灌水,我們就知道,不能一桶水一下子倒進去,肯定會濺出來,要一開始慢慢的倒,然后發現總能夠倒進去,就可以越倒越快。這叫作慢啟動。

一條 TCP 連接開始,cwnd 設置為一個報文段,一次只能發送一個;當收到這一個確認的時候,cwnd 加一,于是一次能夠發送兩個;當這兩個的確認到來的時候,每個確認 cwnd 加一,兩個確認 cwnd 加二,于是一次能夠發送四個;當這四個的確認到來的時候,每個確認 cwnd 加一,四個確認 cwnd 加四,于是一次能夠發送八個。可以看出這是指數性的增長。

漲到什么時候是個頭呢?有一個值 ssthresh 為 65535 個字節,當超過這個值的時候,就要小心一點了,不能倒這么快了,可能快滿了,再慢下來。

每收到一個確認后,cwnd 增加 1/cwnd,我們接著上面的過程來,一次發送八個,當八個確認到來的時候,每個確認增加 1/8,八個確認一共 cwnd 增加 1,于是一次能夠發送九個,變成了線性增長。

但是線性增長還是增長,還是越來越多,直到有一天,水滿則溢,出現了擁塞,這時候一般就會一下子降低倒水的速度,等待溢出的水慢慢滲下去。

擁塞的一種表現形式是丟包,需要超時重傳,這個時候,將 sshresh 設為 cwnd/2,將 cwnd 設為 1,重新開始慢啟動。這真是一旦超時重傳,馬上回到解放前。但是這種方式太激進了,將一個高速的傳輸速度一下子停了下來,會造成網絡卡頓。

(2)快速重傳算法

當接收端發現丟了一個中間包的時候,發送三次前一個包的 ACK,于是發送端就會快速的重傳,不必等待超時再重傳。TCP 認為這種情況不嚴重,因為大部分沒丟,只丟了一小部分,cwnd 減半為 cwnd/2,然后 sshthresh = cwnd,當三個包返回的時候,cwnd = sshthresh + 3,也就是沒有一夜回到解放前,而是還在比較高的值,呈線性增長。

當接收端發現丟了一個中間包的時候,發送三次前一個包的 ACK,于是發送端就會快速的重傳,不必等待超時再重傳。TCP 認為這種情況不嚴重,因為大部分沒丟,只丟了一小部分,cwnd 減半為 cwnd/2,然后 sshthresh = cwnd,當三個包返回的時候,cwnd = sshthresh + 3,也就是沒有一夜回到解放前,而是還在比較高的值,呈線性增長。


就像前面說的一樣,正是這種知進退,使得時延很重要的情況下,反而降低了速度。但是如果你仔細想一下,TCP 的擁塞控制主要來避免的兩個現象都是有問題的。

第一個問題是丟包并不代表著通道滿了,也可能是管子本來就漏水。例如公網上帶寬不滿也會丟包,這個時候就認為擁塞了,退縮了,其實是不對的。

第二個問題是 TCP 的擁塞控制要等到將中間設備都填充滿了,才發生丟包,從而降低速度,這時候已經晚了。其實 TCP 只要填滿管道就可以了,不應該接著填,直到連緩存也填滿。

為了優化這兩個問題,后來有了TCP BBR 擁塞算法。它企圖找到一個平衡點,就是通過不斷的加快發送速度,將管道填滿,但是不要填滿中間設備的緩存,因為這樣時延會增加,在這個平衡點可以很好的達到高帶寬和低時延的平衡。

10.什么是nagle算法?使用時可能會有什么坑?

Nagle算法主要是避免發送小的數據包,要求TCP連接上最多只能有一個未被確認的小分組,在該分組的確認到達之前不能發送其他的小分組。相反,TCP收集這些少量的小分組,并在確認到來時以一個分組的方式發出去。

if there is new data to sendif the window size >= MSS and available data is >= MSSsend complete MSS segment nowelseif there is unconfirmed data still in the pipeenqueue data in the buffer until an acknowledge is receivedelsesend data immediatelyend ifend if end if

從上述算法中看出:

  • 對于MSS的片段直接發送

  • 如果有沒有被確認的data在緩沖區內,先將待發送的數據放到buffer中直到被發送的數據被確認【最多只能有一個未被確認的小分組】

  • 兩種情況置位,就直接發送數據,實際上如果小包,但是沒有未被確認的分組,就直接發送數據。

  • 這里通過一個實驗來看下Nagle算法對于發送的優化:

    實驗要求:Client端每次發送1個字節,將hello發送到Server端,然后server再全部發送給Client,其實要點在于Client的發送,預期的結果是:

  • 我們雖然一個字節一個字節的發,但是在協議中使用Nagle算法,可能會有延時等待的狀況,即將幾個字符合成一個片段進行發送

  • 必須是收到對方的確認之后,才能再次發送

  • 看下實驗的結果:


    從圖中的結果可以看出

  • HELLO 被分成 2個包發送了,應用層調用send 5次,由于Nagle算法,將ELLO合成一個包發送,這樣大可以減少Samll packet的數量,增加TCP傳輸的效率

  • 分成的2個數據包,并沒有連續被發出,這也符合Nagle算法的原則,即TCP連接上最多只能有一個未被確認的小分組,等待收到ACK之后,才發第二個封包。

  • 禁用Nagle算法:

    在默認的情況下,Nagle算法是默認開啟的,Nagle算法比較適用于發送方發送大批量的小數據,并且接收方作出及時回應的場合,這樣可以降低包的傳輸個數。同時協議也要求提供一個方法給上層來禁止掉Nagle算法

    當你的應用不是連續請求+應答的模型的時候,而是需要實時的單項的發送數據并及時獲取響應,這種case就明顯不太適合Nagle算法,明顯有delay的。

    linux提供了TCP_NODELAY的選項來禁用Nagle算法。
    禁用方法:

    setsockopt(client_fd, SOL_TCP, TCP_NODELAY,(int[]){1}, sizeof(int));

    來看下禁用后同樣發送Hello的實驗結果

    從實驗結果中可以得出如下結論:

  • 禁止Nagle算法,每一次send,都會組一個包進行發送,HELLO被分成5個小包分別發送
  • 2.不用等待ACK,可以連續發送

    Delay ACK and Nagle

    Nagle指出Nagle算法與Delay ACK機制有共存的情況下會有一些非常糟糕的狀況,比如舉一個場景:PC1和PC2進行通信,PC1發數據給PC2,PC1使用Nagle算法,PC2有delay ACK機制

    1. PC1發送一個數據包給PC2,PC2會先不回應,delay ACK 2. PC1再次調用send函數發送小于MSS的數據,這些數據會被保存到Buffer中,等待ACK,才能再次被發送

    從上面的描述看,顯然已經死鎖了,PC1在等待ACK,PC2在delay ACK,那么解鎖的代價就是Delay ACK的Timer到期,至少40ms[40ms~500ms不等],也就是2種算法在通信的時候,會產生不必要的延時!

    可以看下實驗的圖示, 9包是發送H字符到server,可以看到隔了30ms的delay ack延時才等到數據,發送一個DATA+ACK包,在這個時間段內其實也是用包發送的,但是nagle算法是要等待ACK的到來才能發包的,所以也會看到11號包要在ACK包之后。如果30ms延時仍然沒有數據,就是我們上述說的那樣白白的等待一個delay ack超時。

    如何來解決這種問題?

    其實Nagle算法本身的立意是好的,避免網絡充斥著過多的小包,提高網絡傳輸的效率,同時Delay ACK也是為了提高TCP的性能,不過二者遇到了,就比較悲劇了。其實在RFC中已經提供了一個用戶級別的解決方案,即避免 write–write–read的這種寫法,write–read–write–read 以及write–write–write都是OK的。假設這里有數據要發送,這個數據分為頭部和數據部分,2部分發送,然后再回讀響應,寫法如下

    1.write(header)2.write(body)3.read(response)服務器read寫法如下1. read(request)2. process(request)3. write(response)

    應用程序使能了Nagle算法,第一個header是一定能夠發送出去的,因為前面沒有帶確認的數據,服務器端接收到header之后,也發現是不完全的,還會再次等待request,同時要delay ACK,再次發write的時候,發現沒有ACK,也會等待ACK延遲發送。這樣只能超時才能再次傳輸。

    這個問題的產生,主要是Nagle和delay ACK 副作用以及write write read的程式造成的。一般寫程序的時候不推薦這樣的寫法。如何解決? 可能想到的就是上面的禁止掉Nagle算法,這也是一種辦法,不過這種辦法同時也會讓網絡充斥小包,降低效率。對于應用程序來講,只要避免write-wirte-read的這種寫法就可以避免掉問題,比如write一塊去寫,一次寫成功,就一個包發過去了,就沒有等待delay的過程了!所以寫程序的時候還是要注意再注意。

    11.http狀態碼301和302是代表什么?403和304代表什么?500,502,503,504分別代表什么?



    12.HTTP中的keep-alive和TCP中keepalive又有什么區別?

    (1)TCP : keepalive,保持活躍的機制
    原理:
    定義一個時間段,在這個時間段內,如果沒有任何連接相關的活動,TCP 保活機制會開始作用,每隔一個時間間隔,發送一個探測報文,該探測報文包含的數據非常少,如果連續幾個探測報文都沒有得到響應,則認為當前的 TCP 連接已經死亡,系統內核將錯誤信息通知給上層應用程序。

    上述的可定義變量,分別被稱為保活時間、保活時間間隔和保活探測次數。在 Linux 系統中,這些變量分別對應 sysctl 變量net.ipv4.tcp_keepalive_time、net.ipv4.tcp_keepalive_intvl、 net.ipv4.tcp_keepalve_probes,默認設置是 7200 秒(2 小時)、75 秒和 9 次探測。

    如果開啟了 TCP 保活,需要考慮以下幾種情況:
    1.第一種,對端程序是正常工作的。當 TCP 保活的探測報文發送給對端, 對端會正常響應,這樣 TCP 保活時間會被重置,等待下一個 TCP 保活時間的到來。

    2.第二種,對端程序崩潰并重啟。當 TCP 保活的探測報文發送給對端后,對端是可以響應的,但由于沒有該連接的有效信息,會產生一個 RST 報文,這樣很快就會發現 TCP 連接已經被重置。

    3.第三種,是對端程序崩潰,或對端由于其他原因導致報文不可達。當 TCP 保活的探測報文發送給對端后,石沉大海,沒有響應,連續幾次,達到保活探測次數后,TCP 會報告該 TCP 連接已經死亡。

    TCP 保活機制默認是關閉的,當我們選擇打開時,可以分別在連接的兩個方向上開啟,也可以單獨在一個方向上開啟。如果開啟服務器端到客戶端的檢測,就可以在客戶端非正常斷連的情況下清除在服務器端保留的“臟數據”;而開啟客戶端到服務器端的檢測,就可以在服務器無響應的情況下,重新發起連接。

    (2)區別
    1、TCP連接往往就是我們廣義理解上的長連接,因為它具備雙端連續收發報文的能力;開啟了keep-alive的HTTP連接,也是一種長連接,但是它由于協議本身的限制,服務端無法主動發起應用報文。

    2、**TCP中的keepalive是用來保鮮、保活的;**HTTP中的keep-alive機制主要為了讓支撐它的TCP連接活的的更久,所以通常又叫做:HTTP persistent connection(持久連接) 和 HTTP connection reuse(連接重用)。

    13.https握手的過程?

    14.什么是httpdns?傳統dns有什么問題?

    1.什么是httpdns

    HTTPNDS 其實就是,不走傳統的 DNS 解析,而是自己搭建基于 HTTP 協議的 DNS 服務器集群,分布在多個地點和多個運營商。
    當客戶端需要 DNS 解析的時候,直接通過 HTTP 協議進行請求這個服務器集群,得到就近的地址

    2.傳統dns有什么問題?

    2.1 域名緩存問題
    它可以在本地做一個緩存,也就是說,不是每一個請求,它都會去訪問權威 DNS 服務器,而是訪問過一次就把結果緩存到自己本地,當其他人來問的時候,直接就返回這個緩存數據。

    這就相當于導游去過一個飯店,自己腦子記住了地址,當有一個游客問的時候,他就憑記憶回答了,不用再去查地址簿。這樣經常存在的一個問題是,人家那個飯店明明都已經搬了,結果作為導游,他并沒有刷新這個緩存,結果你辛辛苦苦到了這個地點,發現飯店已經變成了服裝店,你是不是會非常失望?

    另外,有的運營商會把一些靜態頁面,緩存到本運營商的服務器內,這樣用戶請求的時候,就不用跨運營商進行訪問,這樣既加快了速度,也減少了運營商之間流量計算的成本。在域名解析的時候,不會將用戶導向真正的網站,而是指向這個緩存的服務器。

    很多情況下是看不出問題的,但是當頁面更新,用戶會訪問到老的頁面,問題就出來了。例如,你聽說一個餐館推出了一個新菜,你想去嘗一下。結果導游告訴你,在這里吃也是一樣的。有的游客會覺得沒問題,但是對于想嘗試新菜的人來說,如果導游說帶你去,但其實并沒有吃到新菜,你是不是也會非常失望呢?

    再就是本地的緩存,往往使得全局負載均衡失敗,因為上次進行緩存的時候,緩存中的地址不一定是這次訪問離客戶最近的地方,如果把這個地址返回給客戶,那肯定就會繞遠路。

    就像上一次客戶要吃西湖醋魚的事,導游知道西湖邊有一家,因為當時游客就在西湖邊,可是,下一次客戶在靈隱寺,想吃西湖醋魚的時候,導游還指向西湖邊的那一家,那這就繞的太遠了。

    2.2 域名轉發問題

    緩存問題還是說本地域名解析服務,還是會去權威 DNS 服務器中查找,只不過不是每次都要查找。可以說這還是大導游、大中介。還有一些小導游、小中介,有了請求之后,直接轉發給其他運營商去做解析,自己只是外包了出去。

    這樣的問題是,如果是 A 運營商的客戶,訪問自己運營商的 DNS 服務器,如果 A 運營商去權威 DNS 服務器查詢的話,權威 DNS 服務器知道你是 A 運營商的,就返回給一個部署在 A 運營商的網站地址,這樣針對相同運營商的訪問,速度就會快很多。

    但是 A 運營商偷懶,將解析的請求轉發給 B 運營商,B 運營商去權威 DNS 服務器查詢的話,權威服務器會誤認為,你是 B 運營商的,那就返回給你一個在 B 運營商的網站地址吧,結果客戶的每次訪問都要跨運營商,速度就會很慢。

    2.3 出口 NAT 問題
    網關在出口的時候,很多機房都會配置NAT,也即網絡地址轉換,使得從這個網關出去的包,都換成新的 IP 地址,當然請求返回的時候,在這個網關,再將 IP 地址轉換回去,所以對于訪問來說是沒有任何問題。

    但是一旦做了網絡地址的轉換,權威的 DNS 服務器,就沒辦法通過這個地址,來判斷客戶到底是來自哪個運營商,而且極有可能因為轉換過后的地址,誤判運營商,導致跨運營商的訪問。

    2.4域名更新問題
    本地 DNS 服務器是由不同地區、不同運營商獨立部署的。對域名解析緩存的處理上,實現策略也有區別,有的會偷懶,忽略域名解析結果的 TTL 時間限制,在權威 DNS 服務器解析變更的時候,解析結果在全網生效的周期非常漫長。但是有的時候,在 DNS 的切換中,場景對生效時間要求比較高。

    例如雙機房部署的時候,跨機房的負載均衡和容災多使用 DNS 來做。當一個機房出問題之后,需要修改權威 DNS,將域名指向新的 IP 地址,但是如果更新太慢,那很多用戶都會出現訪問異常。

    這就像,有的導游比較勤快、敬業,時時刻刻關注酒店、餐館、交通的變化,問他的時候,往往會得到最新情況。有的導游懶一些,8 年前背的導游詞就沒換過,問他的時候,指的路往往就是錯的。

    2.5解析延遲問題
    DNS 的查詢過程需要遞歸遍歷多個 DNS 服務器,才能獲得最終的解析結果,這會帶來一定的時延,甚至會解析超時。

    15.開放性問題:從網絡角度,如何優化性能?

    總結

    以上是生活随笔為你收集整理的网络相关面试题(持续更新)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。