近期看完了《網絡是如何鏈接的》這本書,以爲有收穫。可是若是不造成文字的話,印象就不深入,故有此文,鞏固學識的同時,鍛鍊文筆。此書是日本人所寫,旨在展示互聯網的全貌,內容詳盡,涉及面廣,且深刻淺出,老小咸宜。。。好吧,這本書確實寫得不錯,內容涉及軟件、硬件,不光解釋了how,還解釋了why,不難看出做者是個全棧工程師。做者經過「瀏覽器中輸入網址,到屏幕上顯示內容」這條線索,逐層解析,透徹講解各層的功能和做用。下面是個人閱讀總結,不當之處,還請斧正。node
1,輸入網址和敲擊enter按鍵的時候,會有中斷事件產生,這裏我參考了其餘帖子的內容(http://blog.csdn.net/xumingjie1658/article/details/6965176):nginx
當用戶按鍵時,鍵盤接口會獲得一個表明該按鍵的鍵盤掃描碼,同時產生一箇中斷請求。中斷服務程序通知鍵盤中斷服務程序區處理,鍵盤中斷服務程序先從鍵盤接口取得按鍵的掃描碼,而後根據其掃描碼判斷用戶所按的鍵並做相應的處理,最後通知中斷控制器本次中斷結束並實現中斷返回。瀏覽器
鍵盤中斷的大體過程就是這樣,當鍵盤中斷完成以後,也即用戶敲擊「enter」按鍵以後,就觸發了瀏覽器的操做了,就是《網絡是如何鏈接的》一書所闡述的內容了。緩存
2,瀏覽器解析url,生成相應的請求--應用層。好比,瀏覽器發現時 http請求,解析出 www.baidu.com 這個域名。若是本地的dns解析緩存中有這個域名的解析,那麼直接將 http請求委託 tcp 傳輸層進行傳輸。若是沒有,那麼須要向dns服務器發起dns查詢,得到域名對應的ip地址。dns查詢,有遞歸查詢和迭代查詢(也叫循環查詢)兩種。遞歸查詢,就是 A 向 B查詢,B向C查詢,C向D查詢,D查詢到了,將結果返回給C,C返回給B,B再返回給A。這種查詢會形成根域名服務器壓力過大。迭代查詢,就是 A 向B查詢,B告訴A去向C查詢,而後A就向C查詢,C告訴A去向D查詢,而後A就向D查詢,D查詢到了,結果返回給A。dns查詢包都是使用 udp 發送的。經過dns查詢到域名對應的ip地址以後,將http請求委託tcp/ip協議棧進行傳輸。安全
3,應用層委託協議棧進行傳輸,協議棧的tcp傳輸層經過套接字進行傳輸--傳輸層。瀏覽器經過 socket庫向協議棧發出委託,涉及到socket(),connect(),read(),write(),close()等操做。首先是 調用socket()接口,產生一個 文件描述符,而後調用 connect() 接口,進行tcp的三次握手,成功以後,就能夠進行 收發數據了。咱們將 http請求調用write()接口發送出去,其實只是發送到底層的發送緩衝區中,tcp本身會根據時機進行發送,或者根據設置的tcp_nodelay立馬發送。這些操做都是系統調用,會引起用戶態與內核態的切換,因此相對來講比較耗時。若是一個數據包太大,協議棧本身會根據MTU(其實是根據MSS(MTU-40 = 1500-40=1460B))大小自動分割。TCP經過超時重傳、確認機制、滑動窗口等保證可靠性。當服務器收到http請求以後,會將數據返回給瀏覽器所在的客戶端,客戶端調用 read() 接口接收數據,而後斷開鏈接,斷開鏈接這裏有四次通訊。這些 connect(),write(),read(),close()都是委託IP模塊封裝數據進行發送。套接字是由src_ip,src_port,dst_ip,dst_port這四個字段識別的,一個套接字,對應着源端的應用程序 與 目的端的應用程序之間的通訊鏈路。服務器
4,tcp模塊委託IP模塊進行傳輸--網絡層,數據鏈路層。tcp模塊會生成tcp頭部和數據部分,而後交給IP模塊。IP模塊會在tcp頭部再加上一段 IP頭部和MAC頭部。IP頭部是用在網絡間的路由,也即用在互聯網上的尋址。若是有多塊網卡,根據目的ip地址和本地路由表,從中選擇一塊合適的網卡進行發送。MAC頭部,用於局域網內的尋址。MAC地址能夠從arp緩存中獲取,若是沒有,則須要廣播arp請求,獲取對應的mac地址(通常是填寫網關的mac地址)。IP模塊添加完這兩個頭部以後,就交給網卡處理。網絡
5,IP模塊委託網卡進行收發--物理層。網卡收到IP模塊交付的數據以後,會在頭部加上 報頭和起始幀分界符,在尾部加上 幀校驗序列(FCS)。報頭和幀起始分界符,是用來判斷讀取時機的。咱們想象一下,線路上來了一堆 000011111這樣的連續的電信號,咱們是無法同步時鐘信號的,由於他們是連續的高電平或者低電平,沒有電流電壓的變化,沒法判斷應該從哪裏去切分一個比特。因此報頭就給了 010101 這樣的56個比特,讓咱們有足夠的時間去區分比特間的時鐘信號。FCS其實就是CRC校驗碼,用來校驗數據的正確性的,由於傳輸的過程當中,會有噪聲影響,有誤碼率。加上報頭、幀起始分界符、FCS以後,網卡的MAC模塊生產通用信號,由PHY(MAU)模塊轉換成可在網線中傳輸的格式(好比,數據信號和時鐘信號的疊加信號),經過網線發送出去。經過網線發送數據,又分爲全雙工(收發線路獨立)和半雙工(收發線路共用,需進行碰撞檢測),如今應該不多有集線器這種半雙工的設備了。負載均衡
6,數據在局域網內被髮給網關路由器。數據從瀏覽器所在的客戶端的網卡發出,到達交換機,交換機根據MAC地址表查找目的mac地址的轉發端口,若是沒查到則廣播全部端口。交換機上面的交換電路是網格狀的,只要連通一條線路的交換開關,就能夠進行轉發。因此,只要多條線路之間的路線不交叉,就能夠並行傳輸。交換機將數據轉發給網關路由器。socket
7,網關路由器經過ADSL等方式接入互聯網,發給網絡運營商(ISP)。tcp
網關路由器向外網轉發的時候,會有NAT轉換的過程,將內網地址屏蔽。若是網關路由器是轉發的目的端口也是局域網,那麼網關路由器根據數據的IP頭部,路由到相鄰路由器,同時去掉MAC頭部,換上新的MAC頭部,發給相鄰路由器,相鄰的路由器再根據一樣的方法,路由到下一跳,最終到達服務器所在的網絡。
通常來講,服務器若是是放在公司內部,纔會使用上述的方法路由過去。咱們在家庭上網時,網關路由器後面接的是接入網,用於鏈接互聯網。通常家用的接入網方式包括 ADSL、 FTTH、 CATV、 電話線、 ISDN 等, 公司則還可能使用專線。咱們以ADSL爲例,網關路由器(這裏能夠稱爲 互聯網接入路由器)會在網絡包前面加上 MAC 頭部、PPPoE 頭部、PPP 頭 部 總 共 3 種 頭 部, 然 後 發 送 給 ADSL Modem(PPPoE 方式下)。ADSL Modem 將包拆分紅信元,並轉換成電信號發送給分離器。從分離器出來, 就是插電話線的接口, 信號從這裏出來以後, 會經過室內電話線,連到室外電話線,通過架設在電線杆上的電纜,到達電話局,到這裏,就將數據發到了ADSL接入服務商。信號到達電話局後,通過DSLAM拆分紅ATM信元,到達BAS(帶寬接入服務器),BAS 負責將 ATM 信元還原成網絡包並轉發到互聯網內部。BAS和網絡運營商之間創建了一條專用隧道(好比L2TP協議),到達互聯網內部。到這裏,咱們發送的數據,才真正的進入了互聯網。
在剛纔的描述中,從 用戶端的 互聯網接入路由器 到 運營商的 BAS 之間的線路,若是選用 ADSL的方式,就是 ADSL 接入。若是選用光纖,就是光纖接入,也即FTTH。這裏咱們須要注意到,網關路由器,也即互聯網接入路由器,已經具備公網地址,這是在用戶進行了撥號上網設置等操做就完成了的。
8,網絡運營商將數據在互聯網上面轉發,最終到達服務器所在的運營商。而後到達 服務端的 BAS,而後到達服務端所在的接入路由器,服務端能夠將本身暴露在公網上,可是這樣不安全,ip地址也不夠,如今通常不這樣作。更多的做法,是在接入路由器後面部署防火牆,保護局域網的安全。這裏也可能會有NAT解析。
若是客戶端請求量過大,服務器處理不過來,須要分擔負載。辦法有:A,在DNS上面作負載均衡;B,用 nginx 反向代理作負載均衡;C,在客戶端設置緩存;D,用緩存服務器分擔負載(當真實的服務器有內容變化時,去更新緩存服務器),緩存服務器能夠設置客戶端所在的網絡(缺點,不利於真實服務器的管理和控制),也能夠設置在真實服務器所在的網絡(缺點,沒法減小互聯網中的流量),也能夠設置在主流運營商內部(這就是CDN,Content Delivery Network)。
9,數據到達服務器以後,一樣通過網卡-IP模塊-tcp模塊-應用層獲取數據,並進行回覆。服務端的處理,與客戶端略有不一樣,服務端會事先調用 listen()監聽端口,而後調用 accetp() 容許一個客戶端的鏈接,而後使用多路複用技術(select,poll,epoll等)管理多個客戶端的鏈接。咱們假設此時服務端調用read()接口收到客戶端發來的http請求,而後解析請求消息,好比,將url中的地址,轉化爲主機頭對應的虛擬路徑,進行相關的處理,而後調用 write()接口進行回覆。回覆的信息會通過tcp/ip協議棧,到達網卡,發送出去。
10,回覆數據可能會原路返回到 客戶端所在地運營商,也可能經過其餘路由器到達 客戶端所在的運營商。而後運營商經過專用隧道,到達客戶端所在的電話局的BAS,而後BAS經過ADSL或者 FTTH 等線路,到達客戶端所在的網關路由器,或者說 互聯網接入路由器。通過路由器的NAT轉換,發給客戶端。
11,客戶端的網卡從網線中接收信號,並轉化爲數字信號,放到緩衝區,校驗FCS,判斷是不是發給本身的(目的MAC地址是本身的MAC地址),若是不是本身的,則丟棄,不然,放入網卡緩衝區中,併產生中斷,通知計算機收到數據。中斷處理程序讓網卡驅動去處理這個數據,網卡驅動將數據取出來以後交給tcp/ip協議棧處理:IP模塊檢查IP頭部,接收合法包並進行分片重組(如有必要),而後tcp模塊根據IP頭部中的ip地址和tcp頭部中的端口號,找到對應套接字,回覆確認包,將數據放入接收緩衝區,等待應用程序讀取。
14,瀏覽器調用 read()操做,陷入內核,讀取服務端返回的數據,而後返回用戶態,進行相關的處理,通過頁面渲染,展現頁面文字、圖片、音視頻等信息。
總結一下,簡要流程是:
1,敲擊enter按鍵,產生中斷,鍵盤中斷服務程序解析這個按鍵,觸發了瀏覽器的解析操做(瀏覽器如何捕獲enter事件,我還不太清楚)。
2,瀏覽器解析url中的域名,但願能知道 域名對應的ip地址。先看本地的dns緩存,若是沒有,則發送dns查詢包進行查詢。
3,瀏覽器封裝http請求, 調用 connect() 與服務器進行tcp的三次握手,而後調用 write() 發送http請求。該請求通過 傳輸層,網絡層,數據鏈路層,物理層,從數字信號變成電信號,經由網線發送出去。
4,數據通過交換機轉發,到達網關路由器。咱們假設網關路由器使用 ADSL線路並使用 PPPOE 協議接入互聯網,那麼網關路由器會丟掉收到的數據的 MAC頭部,添加PPP,PPPOE頭部,從新組裝一個MAC頭部,發給 電話局的BAS,再經由專用隧道,接入到運營商,進入互聯網。
5,互聯網上各運營商之間路由轉發,最終到達服務器所在的運營商,通過專用隧道,到達 BAS,而後到達網關路由器。
6,網關路由器通過NAT解析,可能還有ngnix反向代理,通過防火牆,將數據發給服務器。
7,服務器網卡接收數據,逐層傳遞到IP層,傳輸層,應用層。
8,服務器應用層進行處理並回復,逐層委託 傳輸層、IP層、數據鏈路層、物理層,發給網關路由器。
9,網關路由器發給BAS,經隧道發給運營商,進入互聯網。
10,互聯網內路由轉發,達到客戶端所在的運營商,經隧道到達BAS,而後到達客戶端的網關路由器。
11,網關路由器通過NAT解析,發給客戶端。
12,客戶端的網卡接收數據,逐層傳遞到IP層,傳輸層,應用層(也即瀏覽器)。瀏覽器獲取數據以後,進行渲染,展現頁面。後續,http協議還會斷開tcp鏈接。
至此,過程結束。