概覽
本次探索之旅從用戶在瀏覽器中輸入網(wǎng)址(URL)開始。
生成HTTP請求消息
瀏覽器的工作會從對用戶輸入的網(wǎng)址進行解析開始贸人。瀏覽器如何解析網(wǎng)址是我們的第一個看點唾琼。然后瀏覽器會根據(jù)網(wǎng)址的含義來生成請求消息团秽,而請求消息實際的樣子就是我們的第二個看點。
向DNS服務(wù)器查詢Web服務(wù)器的IP地址
瀏覽器如何進行這一操作也是看點之一
全世界DNS服務(wù)器的大接力
全世界共有上萬臺的DNS服務(wù)器晦譬,它們相互借力才能完成IP地址的查詢疤苹,而它們進行接力的方法也是本章看點之一。
委托協(xié)議棧發(fā)送消息
查詢到IP地址之后敛腌,瀏覽器就可以將消息委托給操作系統(tǒng)發(fā)送給Web服務(wù)器了卧土,但這個委托到底是如何完成的呢?這也是本章的看點之一像樊。
生成HTTP請求消息
探索之旅從輸入網(wǎng)址開始
URL的各種格式
盡管URL有各種不同的寫法夸溶,但它們有一個共同點,那就是URL開頭的文字凶硅,即
http:
, ftp:
, file:
, mailto:
缝裁,這部分文字表示瀏覽器應(yīng)當(dāng)使用的訪問方法。我們可以把這部分理解為訪問時使用的協(xié)議類型足绅。
瀏覽器先要解析URL
Web瀏覽器解析URL的過程
省略文件名的情況
http://www.lab.glasscom.com/dir/
對于上面這個URL我們可以這樣理解捷绑,以/
結(jié)尾代表/dir/
后面本來應(yīng)該有的文件名被省略了。這種情況下會訪問事先設(shè)定好的默認(rèn)文件氢妈,大多數(shù)情況下是index.html
或者default.htm
之類的文件名粹污。因此,對于這個例子首量,服務(wù)器就會訪問/dir/index.html
或者/dir/default.htm
壮吩。
還有一些URL是像下面這樣只有Web服務(wù)器的域名的,這也是一種省略了文件名的形式加缘。
http://www.lab.glasscom.com/
這個URL也是以/
結(jié)尾的鸭叙,也就是說它表示訪問一個名叫/
的目錄,由于省略了文件名拣宏,所以結(jié)果就是訪問/index.html
或者/default.htm
這樣的文件沈贝。
那么,下面這個URL又是什么意思呢勋乾?
http://www.lab.glasscom.com
這次連結(jié)尾的/
都省略了宋下。像這樣連目錄名都省略時,就會訪問根目錄下事先設(shè)置的默認(rèn)文件辑莫。
但下面這個例子就更詭異了
http://www.lab.glasscom.com/whatisthis
這種情況一般會按照下面的慣例進行處理:如果Web服務(wù)器上存在名為whatisthis
的文件学歧,則將whatisthis
作為文件名來處理;如果存在whatisthis
的目錄各吨,則將whatisthis
作為目錄名來處理枝笨。因為我們無法創(chuàng)建兩個名字相同的文件和目錄。
瀏覽器的第一步工作就是對URL進行解析。
HTTP的基本思路
HTTP請求消息中包含的內(nèi)容是對什么和進行怎樣的操作兩個部分伺帘,其中“對什么”的部分稱為
URI
昭躺。一般來說忌锯,URI的內(nèi)容是一個存放網(wǎng)頁數(shù)據(jù)的文件名或者是一個CGI程序伪嫁。“進行怎樣的操作”的部分稱為方法偶垮,方法表示需要讓W(xué)eb服務(wù)器完成怎樣的工作张咳,常用方法包括GET
和POST
等。除此之外似舵,HTTP消息中還有一些用來表示附加信息的頭字段脚猾。客戶端向Web服務(wù)器發(fā)送數(shù)據(jù)時砚哗,會先發(fā)送頭字段龙助,然后再發(fā)送數(shù)據(jù)。
在收到請求消息后蛛芥,Web服務(wù)器會根據(jù)這些要求來完成自己的工作提鸟,然后將結(jié)果存放在響應(yīng)消息中。在響應(yīng)消息的開頭有一個狀態(tài)碼仅淑,狀態(tài)碼后面就是頭字段和網(wǎng)頁數(shù)據(jù)称勋。
響應(yīng)消息會被發(fā)送回客戶端,客戶端收到之后涯竟,瀏覽器會從消息中讀出所需的數(shù)據(jù)并顯示在屏幕上赡鲜。到這里,HTTP的整個工作就完成了庐船。
生成HTTP請求消息
對URL進行解析之后银酬,瀏覽器確定了Web服務(wù)器和文件名,接下來就是根據(jù)這些信息來生成HTTP請求消息了筐钟。
HTTP消息的格式
一條請求消息中只能寫一個URI捡硅。如果需要獲取多個文件,必須對每個文件單獨發(fā)送1條請求盗棵。
向DNS服務(wù)器查詢Web服務(wù)器的IP地址
Socket庫提供查詢IP地址的功能
我們的計算機上有相應(yīng)的DNS客戶端壮韭,而相當(dāng)于DNS客戶端的部分稱為DNS解析器。通過DNS查詢IP地址的操作稱為域名解析纹因。
解析器實際上是一段程序喷屋,它包含在操作系統(tǒng)的Socket庫中。Socket庫包含的程序組件可以讓其他的應(yīng)用程序調(diào)用操作系統(tǒng)的網(wǎng)絡(luò)功能瞭恰,而解析器就是這個庫中的其中一種程序組件屯曹。
Socket庫是用于調(diào)用網(wǎng)絡(luò)功能的程序組件集合。
通過解析器向DNS服務(wù)器發(fā)出查詢
解析器的用法非常簡單,只要像下圖一樣寫上解析器的程序名稱gethostbyname
以及Web服務(wù)器的域名www.lab.glasscom.com
就可以了恶耽,這樣就完成了對解析器的調(diào)用密任。
調(diào)用解析器后,解析器會向DNS服務(wù)器發(fā)送查詢消息偷俭,然后DNS服務(wù)器會返回響應(yīng)消息浪讳。響應(yīng)消息中包含查詢到的IP地址,解析器會取出IP地址涌萤,并將其寫入瀏覽器指定的內(nèi)存地址中淹遵。
根據(jù)域名查詢IP地址時,瀏覽器會使用Socket庫中的解析器负溪。
解析器的內(nèi)部原理
當(dāng)瀏覽器調(diào)用解析器時透揣,程序的控制流程就會轉(zhuǎn)移到解析器的內(nèi)部。解析器會根據(jù)DNS的規(guī)格川抡,生成一條表示“請告訴我www.lab.glasscom.com的IP地址”的數(shù)據(jù)辐真,并將它發(fā)送給DNS服務(wù)器。
HTTP消息是用文本編寫的崖堤,但DNS消息是使用二進制數(shù)據(jù)編寫的侍咱。
發(fā)送消息這個操作不是由解析器本身來執(zhí)行,而是要委托給操作系統(tǒng)內(nèi)部的協(xié)議棧來執(zhí)行倘感。這是因為和瀏覽器一樣放坏,解析器本身也不具備使用網(wǎng)絡(luò)收發(fā)數(shù)據(jù)的功能。解析器調(diào)用協(xié)議棧后老玛,控制流程會再次轉(zhuǎn)移淤年,協(xié)議棧會執(zhí)行發(fā)送消息的操作,然后通過網(wǎng)卡將消息發(fā)送給DNS服務(wù)器蜡豹。
向DNS服務(wù)器發(fā)送消息時麸粮,我們當(dāng)然也需要知道DNS服務(wù)器的IP地址。只不過這個IP地址是作為TCP/IP的一個設(shè)置項目事先設(shè)置好的镜廉,不需要再去查詢了弄诲。Windows的設(shè)置如下圖所示。
全世界DNS服務(wù)器的大接力
DNS服務(wù)器的基本工作
DNS服務(wù)器的基本工作就是接收來自客戶端的查詢消息娇唯,然后根據(jù)消息的內(nèi)容返回響應(yīng)齐遵。來自客戶端的查詢消息包含以下三種信息:域名、Class以及記錄類型塔插。
DNS服務(wù)器上事先保存有前面這三種信息對應(yīng)的記錄數(shù)據(jù)梗摇,DNS服務(wù)器就是根據(jù)這些記錄查找符合查詢請求的內(nèi)容并對客戶端作出相應(yīng)的。
查詢IP地址時我們使用
A
這個記錄類型想许,查詢郵件服務(wù)器時我們要使用MX
類型伶授。當(dāng)記錄類型為MX
時断序,DNS服務(wù)器會在記錄中保存兩種信息,分別是郵件服務(wù)器的域名和優(yōu)先級糜烹。
DNS服務(wù)器會從域名與IP地址的對照表中查找相應(yīng)的記錄违诗,并返回IP地址。
域名的層次結(jié)構(gòu)
互聯(lián)網(wǎng)中存在著不計其數(shù)的服務(wù)器疮蹦,將這些服務(wù)器的信息全部保存在一臺DNS服務(wù)器中是不可能的诸迟,因此一定會出現(xiàn)DNS服務(wù)器中找不到要查詢的信息的情況。
直接說答案的話很簡單挚币,就是將信息分布保存在多臺DNS服務(wù)器中亮蒋,這些DNS服務(wù)器相互接力配合扣典,從而查找出要查詢的信息妆毕。但這個機制其實有點復(fù)雜。
首先贮尖,DNS服務(wù)器中的所有信息都是按照域名以分層次的結(jié)構(gòu)來保存的笛粘。
一個域的信息是作為一個整體存放在DNS服務(wù)器中的,不能將一個域拆開來存放在多臺DNS服務(wù)器中湿硝。但一臺DNS服務(wù)器中可以存放多個域的信息薪前。
尋找相應(yīng)的DNS服務(wù)器并獲取IP地址
這里的關(guān)鍵在于如何找到我們要訪問的Web服務(wù)器的信息歸哪一臺DNS服務(wù)器管。我們可以采用下面發(fā)的方法关斜。
將負(fù)責(zé)管理下級域的DNS服務(wù)器的IP地址注冊到它們的上級DNS服務(wù)器中示括,然后上級DNS服務(wù)器的IP地址再注冊到更上一級的DNS服務(wù)器中。也就是說痢畜,負(fù)責(zé)管理lab.glasscom.com
這個域的DNS服務(wù)器的IP地址需要注冊到glasscom.com
的DNS服務(wù)器中垛膝,而glasscom.com
域的DNS服務(wù)器的IP地址又需要注冊到com
域的DNS服務(wù)器中。
這樣丁稀,我們就可以通過上級DNS服務(wù)器查詢出下級DNS服務(wù)器的IP地址吼拥,也就可以向下級DNS服務(wù)器發(fā)送查詢請求了。
在互聯(lián)網(wǎng)中线衫,com
和jp
這類域名上面還有一級域
凿可,稱為根域。根域在一般書寫域名時經(jīng)常被忽略授账,一般在域名的最后加上一個句號www.lab.glasscom.com.
枯跑,這個.
就代表根域。根域的服務(wù)器中保管者com
白热、jp
的DNS服務(wù)器的信息敛助。由于上級DNS服務(wù)器保管者所有下級DNS服務(wù)器的信息,所以我們可以從根域開始一路往下找到任意一個域的DNS服務(wù)器棘捣。除此之外辜腺,我們還需要將根域的DNS服務(wù)器信息保存在互聯(lián)網(wǎng)中所有的DNS服務(wù)器中休建。分配給根域DNS服務(wù)器的IP地址在全世界僅有13個,而且這些地址幾乎不發(fā)生變化评疗,因此將這些地址保存在所有的DNS服務(wù)器中也不是一件難事测砂。
我們用一張圖來看一下這個過程是如何進行的。
通過緩存加快DNS服務(wù)器的響應(yīng)
有時候并不需要從最上級的根域開始查找百匆,因為DNS服務(wù)器有一個緩存功能砌些,可以記住之前查詢過的域名。如果要查詢的域名和相關(guān)信息已經(jīng)在緩存中加匈,那么就可以直接返回響應(yīng)存璃,緩存可以減少查詢所需的時間。
由于信息被緩存后雕拼,原本的注冊信息可能會發(fā)生改變纵东,這時緩存中的信息就有可能是不正確的。因此啥寇,DNS服務(wù)器中保存的信息都設(shè)置一個有效期偎球,當(dāng)緩存中的信息超過有效期后,數(shù)據(jù)就會從緩存中被刪除辑甜。
委托協(xié)議棧發(fā)送消息
數(shù)據(jù)收發(fā)操作概覽
知道了IP地址之后衰絮,就可以委托操作系統(tǒng)內(nèi)部的協(xié)議棧向這個目標(biāo)IP地址,也就是我們要訪問的Web服務(wù)器發(fā)送消息了磷醋。
和向DNS服務(wù)器查詢IP地址的操作一樣猫牡,這里也需要使用Socket庫中的程序組件。不過邓线,查詢IP地址只需要調(diào)用一個程序組件就可以了淌友,而這里需要按照指定的順序調(diào)用多個程序組件。
向操作系統(tǒng)內(nèi)部的協(xié)議棧發(fā)出委托時褂痰,需要按照指定的順序來調(diào)用Socket庫中的程序組件亩进。
使用Socket庫來收發(fā)數(shù)據(jù)的操作過程如下圖所示。簡單來說缩歪,收發(fā)數(shù)據(jù)的兩臺計算機之間連接了一條數(shù)據(jù)通道归薛,數(shù)據(jù)沿著這條通道流動,最終到達目的地匪蝙。
這條管道并不是一開始就有的主籍,在進行收發(fā)數(shù)據(jù)操作之前,雙方需要先建立起這條管道逛球。建立管道的關(guān)鍵在于管道兩端的數(shù)據(jù)出入口千元,這些出入口稱為套接字。我們需要先創(chuàng)建套接字颤绕,然后再將套接字連接起來形成管道幸海。服務(wù)器程序一般會在啟動后就創(chuàng)建好套接字并等待客戶端連接管道祟身。管道在連接時是由客戶端發(fā)起的,但在斷開時可以由客戶端或服務(wù)器任意一方發(fā)起物独。其中一方斷開后袜硫,另一方也會隨之?dāng)嚅_,當(dāng)管道斷開后挡篓,套接字也會被刪除婉陷。到此為止,通信操作就結(jié)束了官研。
綜上所述秽澳,收發(fā)數(shù)據(jù)的操作分為若干個階段,可以大致總結(jié)為以下4個戏羽。
- 創(chuàng)建套接字(創(chuàng)建套接字階段)
- 將管道連接到服務(wù)器端的套接字上(連接階段)
- 收發(fā)數(shù)據(jù)(通信階段)
- 斷開管道并刪除套接字(斷開階段)
在每個階段担神,Socket庫中的程序組件都會被調(diào)用來執(zhí)行相關(guān)的數(shù)據(jù)收發(fā)操作。這四個操作都是由操作系統(tǒng)中的協(xié)議棧來執(zhí)行的蛛壳,是由瀏覽器委托杏瞻。這些委托操作都是通過調(diào)用Socket庫中的程序組件來執(zhí)行的所刀,但這些數(shù)據(jù)通信用的程序組件其實僅僅充當(dāng)了一個橋梁的作用衙荐,并不執(zhí)行任何實質(zhì)性的操作,應(yīng)用程序的委托內(nèi)容最終會被原原本本地傳遞給協(xié)議棧浮创。因此后文會將Socket庫和協(xié)議椨且鳎看成一個整體來講解。
當(dāng)調(diào)用Socket庫中的程序組件時斩披,應(yīng)用程序所指定的參數(shù)會通過Socket庫的程序組件傳遞給協(xié)議棧溜族,并由協(xié)議棧來實際執(zhí)行相應(yīng)的操作。
下面我們來探索一下應(yīng)用程序(瀏覽器)委托收發(fā)數(shù)據(jù)的過程垦沉。這個過程的關(guān)鍵點是按照一定的順序調(diào)用Socket庫中的若干個程序組件煌抒。
創(chuàng)建套接字階段
客戶端創(chuàng)建套接字的操作非常簡單,只要調(diào)用Socket庫中的socket
程序組件就可以了厕倍。和調(diào)用解析器一樣寡壮,調(diào)用socket
之后,控制流程會轉(zhuǎn)移到socket內(nèi)部并執(zhí)行創(chuàng)建套接字的操作讹弯。
套接字創(chuàng)建完成后况既,協(xié)議棧會返回一個描述符,應(yīng)用程序會將收到的描述符放在內(nèi)存中组民。描述符是用來識別不同的套接字的棒仍,因為實際上計算機中會同時進行多個數(shù)據(jù)的通信操作,有多個數(shù)據(jù)收發(fā)操作在進行臭胜,也就需要創(chuàng)建多個不同的套接字莫其,描述符就是幫助我們來識別出特定的套接字的方法癞尚。
應(yīng)用程序是通過“描述符”這一類似號碼牌的東西來識別套接字的。
連接階段:把管道接上去
接下來我們需要委托協(xié)議棧將客戶端創(chuàng)建的套接字與服務(wù)器那邊的套接字連接起來乱陡。應(yīng)用程序通過調(diào)用Socket庫中的名為connect
的程序組件來完成這一操作否纬。當(dāng)調(diào)用connect時,需要指定描述符蛋褥、服務(wù)器IP地址和端口號這三個參數(shù)临燃。
這里解釋一下端口號,通過IP地址我們能識別出網(wǎng)絡(luò)上的某臺計算機烙心。但連接操作的對象是某個具體的套接字膜廊,而通過端口號我們可以明確識別出某臺具體的計算機上的某個具體的套接字。
如果說描述符是用來在一臺計算機內(nèi)部識別套接字的機制淫茵,那么端口號就是用來讓通信的另一方能夠識別出套接字的機制爪瓜。
但網(wǎng)址上好像并沒有端口號?也不能像IP地址一樣去問DNS服務(wù)器匙瘪,那怎么辦铆铆?
其實服務(wù)器上所使用的端口號是根據(jù)應(yīng)用的種類實現(xiàn)規(guī)定好的,比如Web是80號端口丹喻,電子郵件是25號端口薄货。只要制定了實現(xiàn)規(guī)定好的端口號,就可以鏈接到相應(yīng)的服務(wù)器程序的套接字碍论。
而客戶端自己在創(chuàng)建套接字時谅猾,協(xié)議棧會為這個套接字隨便分配一個端口號。接下來鳍悠,當(dāng)協(xié)議棧執(zhí)行連接操作時税娜,會將這個隨便分配的端口號通知給服務(wù)器。
總結(jié):
當(dāng)調(diào)用connect后藏研,協(xié)議棧就會執(zhí)行連接操作敬矩。當(dāng)連接成功后,協(xié)議棧會將對方的IP地址和端口號等信息保存在套接字中蠢挡,這樣就可以開始收發(fā)數(shù)據(jù)了弧岳。
描述符:應(yīng)用程序用來識別套接字的機制
IP地址和端口號:客戶端和服務(wù)器之間用來識別對方套接字的機制
通信階段:傳遞消息
只要將數(shù)據(jù)送入套接字,數(shù)據(jù)就會被發(fā)送到對方的套接字中袒哥。這個操作需要Socket庫中的wirte
程序組件來完成缩筛。應(yīng)用程序需要在內(nèi)存中準(zhǔn)備好要發(fā)送的數(shù)據(jù),在這個具體例子里堡称,根據(jù)用戶輸入的網(wǎng)址生成的HTTP請求消息就是我們要發(fā)送的數(shù)據(jù)瞎抛。
當(dāng)消息返回后,需要執(zhí)行的是接收消息的操作却紧。接收消息的操作是通過Socket庫中的read
程序組件委托協(xié)議棧來完成的桐臊。調(diào)用read時需要制定用于存放接收到的響應(yīng)消息的內(nèi)存地址胎撤,這一內(nèi)存地址稱為接收緩沖區(qū)。
斷開階段:收發(fā)數(shù)據(jù)結(jié)束
當(dāng)瀏覽器收到數(shù)據(jù)之后断凶,收發(fā)數(shù)據(jù)的過程就結(jié)束了伤提。我們需要調(diào)用Socket庫的close
程序組件進入斷開階段。最終认烁,連接在套接字之間的管道會被斷開肿男,套接字本身也會被刪除。
斷開的過程如下却嗡。Web使用的HTTP協(xié)議規(guī)定舶沛,當(dāng)Web服務(wù)器發(fā)送完響應(yīng)消息之后,應(yīng)該主動執(zhí)行斷開操作窗价。
這就是HTTP的工作過程如庭,HTTP協(xié)議將HTML文檔和圖片都作為單獨的對象來處理。因此撼港,如果一個網(wǎng)頁中包含很多張圖片坪它,就必須重復(fù)進行很多次連接、收發(fā)數(shù)據(jù)帝牡、斷開的操作往毡。重復(fù)連接和斷開顯然是效率很低的。因此后來人們又設(shè)計出了能夠在一次連接中收發(fā)多個請求和相應(yīng)的方法否灾,在HTTP版本1.1中就可以使用這種方法卖擅。在這種情況下,當(dāng)所有數(shù)據(jù)都請求完成后墨技,瀏覽器會主動觸發(fā)斷開連接的操作。
專業(yè)名詞
URL
- Uniform Resource Locator挎狸,統(tǒng)一資源定位符
FTP
- File Transfer Protocol扣汪,文件傳送協(xié)議
- 這是一種在上傳、下載文件時使用的協(xié)議锨匆。使用FTP協(xié)議來傳送文件的程序也被叫做FTP崭别。
HTTP
- Hypertext Transfer Protocol,超文本傳送協(xié)議
URI
- Uniform Resource Identifier恐锣,統(tǒng)一資源標(biāo)識符
DNS
- Domain Name System茅主,域名服務(wù)系統(tǒng)
- 將服務(wù)器名稱和IP地址進行關(guān)聯(lián)是DNS最常見的用法。但DNS的功能并不僅限于此土榴,它還可以將郵件地址和郵件服務(wù)器進行關(guān)聯(lián)诀姚,以及為各種信息關(guān)聯(lián)相應(yīng)的名稱
socket
表示程序組件的名稱
Socket庫
- Socket庫是用于調(diào)用網(wǎng)絡(luò)功能的程序組件集合
套接字
- 表示管道兩端的接口
協(xié)議棧
- 操作系統(tǒng)內(nèi)部的網(wǎng)絡(luò)控制軟件,也叫“協(xié)議驅(qū)動”“TCP/IP驅(qū)動”等玷禽。
郵件服務(wù)器優(yōu)先級
- 當(dāng)一個郵件地址對應(yīng)多個郵件服務(wù)器時赫段,需要根據(jù)優(yōu)先級來判斷哪個郵件服務(wù)器是優(yōu)先的呀打。優(yōu)先級數(shù)值較小的郵件服務(wù)器代表更優(yōu)先
UDP
- User Datagram Protocol,用戶數(shù)據(jù)報協(xié)議