背景
網絡,網絡...
雖然只是一個簡單的名詞,但是她的背后卻掩藏着太多太多的故事以及知識。
窮其編程的一生,或許也只能探索出那冰山一角,嗨...
小時雖知,學海無涯,卻毫不知意。玩乃天性,卻空流時光。憾...
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轉換為實際的文件名,並作出響應。格式如下。
到這里,我們所有的內容就到這里了。
最后,祝大家每天身體健康,開心編程,看的開心。嘿...