帶你探索網路裡的那些祕密
背景
網路,網路...
雖然只是一個簡單的名詞,但是她的背後卻掩藏著太多太多的故事以及知識。
窮其程式設計的一生,或許也只能探索出那冰山一角,嗨...
小時雖知,學海無涯,卻毫不知意。玩乃天性,卻空流時光。憾...
so,矯情之餘,我們來探索一下網路究竟是怎麼傳輸的。
概述
探索網路的範圍,都在上圖有所展示(另存為看大圖)。
正文
一. 生成HTTP請求訊息
開啟一個網站,都是從瀏覽器中輸入網址開始,我們的探索也是從這裡開始。
https: 是協議,告訴瀏覽器我們要訪問的目標,而https: 代表的就是訪問Web伺服器,當然也有其他的協議。比如ftp:訪問的就是FTP伺服器等。
sexyphoenix.github.io 是Web伺服器域名,可以告訴我們在哪裡可以找到Web伺服器。
about/ 是Web伺服器裡面的檔案路徑名,這裡的about是目錄名,全路徑可能是about/index.md,而index.md應該被github掩藏了。
瀏覽器首先要做的就是對URL進行解析,知道我們要訪問的是sexyphoenix.github.io這個Web伺服器上檔案路徑為about目錄下的預設檔案。
知道了要訪問的目標,接下來瀏覽器就要生成HTTP的請求資訊,介紹到這,就要聊一聊HTTP協議了。
HTTP協議規定了客戶端和伺服器通訊的內容和步驟,簡單來說,就是兩個部分“對什麼”做“怎樣的操作”。
“對什麼”上面已經解析過了,“怎樣的操作”就是HTTP主要的方法:POST、GET、DELETE、PUT等。HTTP格式看下圖。
二、查詢Web伺服器的IP地址
生成HTTP資訊之後,接下來,我們就要傳送資訊給Web伺服器了。但此時我們突然發現我們只有Web伺服器的域名,並不知道伺服器究竟在哪裡。
那麼我們應該如何像現實中送快遞一樣,快速的定位到哪一幢哪一室,講到這裡,想必大家都有所意會了,IP。
IP地址
IP地址實際就是4個位元組,32位元的數字,每8個位元為1組,具體看下圖十進位制表示。
我們傳送的資訊,就是通過子網的整合器找到最近的路由器,再通過路由器(基於IP設計)找到最優抵達Web伺服器的路由器,這樣不斷的查詢網路中的路由器節點,最終抵達Web伺服器。
注意,我們的Web伺服器的IP是最終的目的地,它是貫穿路由器---N---路由器---Web伺服器整個環節的,是判斷整個網路走向的依據,存在控制資訊中。
路由器都有自己的IP,路由器到路由器就是根據Web伺服器的IP(走向),通過本身的IP來移動。
到這裡,我們也就瞭解清楚了通過IP,傳送的資訊最終可以抵達Web伺服器。
那麼,我們現在的問題就是如何通過Web伺服器的域名找到它的IP? 講到這裡,想必大家又都有所意會了,DNS。
域名解析
簡單的來說,DNS伺服器維持了一系列關係表,也就是域名和IP對於的關係表。瀏覽器向最近的DNS伺服器詢問“sexyphoenix.github.io”的IP地址是多少,DNS伺服器會回答Web伺服器IP為xxx。這一步也叫域名解析
講到這裡,我們就要深究一下,瀏覽器究竟是怎樣向DNS伺服器傳送查詢的?
首先,我們要清楚一點,瀏覽器等應用程式本身是不能傳送資訊的,而是委託給作業系統來發送的。
而作業系統有一個超級出名的庫,Socket庫,它是呼叫網路功能的程式元件集合。
Socket庫裡面有一個函式。
IP資訊 = gethostbyname("sexyphoenix.github.io") # 看,應用程式查詢IP很簡單,呼叫一個函式即可
傳送資料有兩種協議,UDP和TCP,域名查詢用的是UDP。資料短速度快。
介紹了域名解析,下面來了解一下DNS伺服器的工作。
DNS伺服器
在上面已經提到過了,DNS伺服器維護了一個關係表,上圖的型別A表示域名對應IP地址,MX表示域名對應的郵箱伺服器,不同的型別,返回的資訊有所不同。
DNS伺服器的工作就是根據域名和型別,查詢相關的記錄,並嚮應用程式返回響應資訊。
DNS伺服器查詢
全球共有13臺根域名伺服器,根域名用“.”表示,其次才是下面的一級域名“com.”、“net.”等,我們平時訪問的域名“sexyphoenix.github.io.”後面有一個點,平時被省略。
我們用一張圖來看下查詢順序,更清楚些。
先找最近的DNS伺服器(一般是本機設定的),沒有再從根域找,然後不斷的向下找,直到找到我們Web伺服器IP所在的DNS伺服器。
三、TCP/IP傳輸資料
通過DNS伺服器查詢,我們已經得到的Web伺服器的IP,接下來就要開始傳送資料了。而這部分也是比較難寫的一部分,因為我們要深入協議棧的內部,去了解它的結構。
我們都知道資料的傳輸,都是由上層委託給下層工作的。應用程式將傳送的資訊的行為委派給了作業系統,而作業系統內部就是通過協議棧來工作的。
來看下作業系統協議棧圖。
上部分是TCP協議和UDP協議,都是負責資料的收發部分,區別在於TCP是面向連線的,是一種可靠的協議,而UDP只負責傳送,不保證準確到達。
下部分是IP協議,負責傳送網路包,其中還包括ICMP協議(檢查傳送過程是否存在錯誤)和ARP協議(查詢MAC地址)。
資料收發
在查詢IP地址的時候,我們用到了Socket庫,這裡同樣也需要用到它。
不過我們這裡需要呼叫多個元件,才能實現資料的收發,從功能上可以分為四個部分。
建立套接字 (new Socket)
連線伺服器的套接字 (connection)
收發資料 (write、read)
刪除套接字 (close)
在講之前,我們先了解下套接字。
套接字在資料收發中是相當重要的,它是一塊記憶體空間,裡面存放著很重要的的控制資訊。
這些控制資訊存放著通訊物件的IP地址、埠、連線狀態、響應時間、資料收發情況等等,只有這些存在,才能知道資料傳送到哪裡,又傳送了多少,有沒有錯誤等等。
建立套接字
建立套接字還是非常簡單的,直接呼叫Socket庫中的socket元件即可,建立完成之後會返回一個識別符號,識別符號的主要作用就是為了區別不同的套接字。
連線伺服器的套接字
連線伺服器用到的是connect元件,引數有識別符號、伺服器的IP、埠等,相當於和伺服器之間連線了一條資料管道,後期資料在其中流通。
同時在這裡也會發生著名的“三次握手”。
在剛發生連線階段,管道里面是沒有資料的,但是會有控制資訊,這些控制資訊包括TCP頭部,乙太網頭部、IP頭部。
控制資訊
根據層級來,我們會先生成TCP頭部,TCP頭部格式有很多欄位,其中重要的就是雙方的埠,序號,ACK號,控制位,視窗等。稍微瞭解一下這些欄位的作用。
埠
埠和IP是一同存在的,在網際網路早期的時候,公司聯網都是直接用公網IP的,但隨著網際網路的發展,公網IP越來越少,於是就出現了公網和內網的區別。
內網IP範圍
10.0.0.0 ~ 10.255.255.255
172.16.0.0 ~ 172.31.255.255
192.168.0.0 ~ 192.168.255.255
每個公司的內部都使用這些內網IP,再通過唯一的一個公網IP訪問網際網路,這樣就可以節省大量的公網IP。
那麼公司的這些設定內網IP的電腦是如何通過唯一的公網IP訪問網際網路呢? 網際網路返回的資訊又是怎麼通過唯一的公網IP,定位到公司的某一臺電腦上的?
地址轉換(NAT),這個技術就解決了上面的問題,它的原理就是在轉發網路包時對IP頭部地址和埠進行改寫。
而埠在其中的作用至關重要,它可以讓路由器(公網IP)知道是那一臺內網的電腦與網際網路通訊,具體看下圖。
公司IP為192.168.23.183的電腦,通過49158埠向網際網路傳送連線,當到達公司的公網路由器的時候,路由器的IP模組會對控制資訊進行改寫,最後變成IP為121.225.19.59,埠為1001和通訊物件通訊。
同時將這條記錄儲存在路由器上,當通訊物件返回資訊時,會通過表格中的資訊找到對應的內網電腦IP。
序號
傳送方告訴接收方該網路包在所有傳送的資料的第幾個位元組,序號的初始值是在連線階段隨機生成的(防止攻擊者猜到),在下面的收發資料階段,就是以這個序號為基數。
ACK號
接收方告訴傳送發已經收到所有資料的第幾個位元組,相當於序號+傳送的資料長度。
控制位
每一個位元代表不同的控制資訊,看下圖。
圖中解釋了比較重要的控制位。
視窗
接收方告訴傳送方的視窗大小,如果接收方接受的速度比較慢,一起傳送的資料量就會變小相當於控制了我們傳送資料的快慢。
介紹了TCP頭部的關鍵欄位,接下來我們開始進入連線。
首先,我們會將客戶端的控制位的SYN(1)、生成隨機序號M、視窗大小等,再通過其他層,到達伺服器端(第一次握手)。
伺服器收到SYN為1的資訊,知道客戶端要和我連線,生成ACK號(M+1)、伺服器隨機序號N(通訊是雙向的,這時的伺服器也相當於傳送方)、控制位SYN(1)、視窗等傳送(第二次握手)。
客戶端收到伺服器端的資訊,得到ACK號,知道連線正常,傳送ACK號(N+1,伺服器端的序號)、控制位SYN(1),告訴伺服器已建立連線(第三次握手)。
收發資料
管道連線建立成功後,就進入了資料收發階段。
我們傳送的資訊一般都是比較大的,不可能一次性發送完畢,所以在TCP模組,就會將應用資料切分成資料塊,切分的每個資料塊(MSS,最大資料長度)加上TCP頭部,IP頭部不能超過MTU大小(MTU,最大傳輸單元)。
接下來,交給IP模組,生成IP頭部和MAC頭部資訊,再通過網絡卡驅動,網絡卡裝置將數字資訊轉變成電訊號,傳輸到接收方。接收方收到資訊,會返回ACK號,重複以上步驟,直到接收方收到所有資料。
接收方收到全部資料後,同樣會向傳送方傳送資料,下面的步驟都和上面差不多了,這裡不再贅述。
刪除套接字
和接收方通訊完成之後,套接字不會再使用,這時就可以刪除套接字了。
套接字刪除可以由任何一方發起,這裡假設伺服器端發起,下面就來講講著名的“四次揮手”。
接收方收到全部資料後,等待一會就會刪除套接字。
伺服器生成斷開資訊,即將TCP的頭部控制位的FIN設定為1,傳送給客戶端。
客戶端返回ACK號,表示傳送的資訊無誤。
客戶端所有資料處理完成後,向伺服器傳送FIN為1的斷開資訊。
伺服器返回ACK號,表示傳送的資訊無誤,等待一會,客戶端和伺服器端都刪除套接字。
講到這裡,資料收發的絕大數內容就講完了,接下來我們聊一聊IP模組。
IP模組
前面提到過,在IP模組會生成IP頭部和乙太網頭部。那麼這兩個頭部究竟有什麼作用?
為了便於理解,我們這裡就講的簡單一些。
傳送的資料到達子網的集線器或者交換機,通過MAC表,找到下一個轉發裝置的MAC地址,以“乙太網協議”傳輸到下一個轉發裝置。
轉發裝置根據目標地址的IP和“IP協議”判斷下一個轉發裝置的IP,再通過MAC地址,傳輸到下一個轉發裝置。
就這樣,經過多個轉發裝置的接力後,網路包最終到達接收方的網路裝置。
總結:IP協議根據目標地址判斷一下個IP轉發裝置的位置,再通過乙太網協議將網路包輸出到下一個轉發裝置。
四、到達Web伺服器
其實在到達Web伺服器之前,我們也應該講講數字訊號是如何轉化為電子訊號的? 資料又是如何通過運營商到達Web伺服器的?
只是這部分實在過於複雜,也多數跟硬體以及運維方向有關,這裡就不講了。
首先,我們來講一講Web伺服器的部署。
Web伺服器的部署有三種方式
直接部署在公司的內網。
公司的內網和Web伺服器分開部署。在接入網之後,部署統一防火牆,再分別進去內網和伺服器。
web伺服器部署在運營商的資料中心。
三種方式自上而下,效能和安全上會越來越好,只是管理上可能會麻煩些。
為了安全和分擔負載,Web伺服器前面會部署防火牆,可能還會有負載均衡器、快取伺服器、內容分發等等。
資料在經過層層過濾後,最終到達Web伺服器,伺服器的程式和上面建立連線的步驟稍有不同。
首先是建立套接字(socket)。
繫結套接字和埠號(bind)。
等待連線(listen)。
接受連線(accept)。
伺服器的程式會一直等待客戶端的連線。
在接收到客戶端的請求後,Web伺服器根據URI轉換為實際的檔名,並作出響應。格式如下。
到這裡,我們所有的內容就到這裡了。
最後,祝大家每天身體健康,開心程式設計,看的開心。嘿...