一、目錄 二、Hi All 三、同一個局域網(wǎng)中不同主機的互聯(lián) 四、跨網(wǎng)段請求百度的服務器 五、百度的響應包如何再打回到你的機器? 六、求關注啦!
這一次,讓我在百度告訴你,當你請求www.baidu.com時都發(fā)生了什么?以及數(shù)據(jù)包經(jīng)歷了怎樣的過程才被轉(zhuǎn)發(fā)到百度的IDC機房的、以及你的電腦又是如何接收到百度的返回的數(shù)據(jù)包的!
這篇文章會串講:IPv4、MAC、DNS、交換機、ARP、路由器、路由表、NAT、NAPT、私網(wǎng)、公網(wǎng)、OSI7層網(wǎng)絡模型、以及不同機器互聯(lián)互通原理等計算機網(wǎng)絡知識點。
好,我們開始吧!
先看個簡單的,同一個局域網(wǎng)中的不同主機A、B之間是如何互聯(lián)交換數(shù)據(jù)的。如下圖:
那,既然是同一個局域網(wǎng)中,說明A、B的ip地址在同一個網(wǎng)段,如上圖就假設它們都在192.168.1.0
網(wǎng)段。
還得再看下面這張OSI 7層網(wǎng)絡模型圖。
主機A向主機B發(fā)送數(shù)據(jù),對主機A來說數(shù)據(jù)會從最上層的應用層一路往下層傳遞。比如應用層使用的http協(xié)議、傳輸層使用的TCP協(xié)議,那數(shù)據(jù)在往下層傳遞的過程中,會根據(jù)該層的協(xié)議添加上不同的協(xié)議頭等信息。
根據(jù)OSI7層網(wǎng)絡模型的設定,對于接受數(shù)據(jù)的主機B來說,它會接收到很多數(shù)據(jù)包!這些數(shù)據(jù)包會從最下層的物理層依次往上層傳遞,依次根據(jù)每一層的網(wǎng)絡協(xié)議進行拆包。一直到應用層取出主機A發(fā)送給他的數(shù)據(jù)。
那么問題來了,主機B怎么判斷它收到的數(shù)據(jù)包是否是發(fā)送給自己的呢?萬一有人發(fā)錯了呢?
答案是:根據(jù)MAC地址,邏輯如下。
if 收到的數(shù)據(jù)包.MAC地址 == 自己的MAC地址{
// 接收數(shù)據(jù)
// 處理數(shù)據(jù)包
}else{
// 丟棄
}
那對于主機A來說,它想發(fā)送給主機B數(shù)據(jù)包,還不能讓主機B把這個數(shù)據(jù)包扔掉,它只能中規(guī)中矩的按以太網(wǎng)網(wǎng)絡協(xié)議要求封裝將要發(fā)送出去的數(shù)據(jù)包,往下傳遞到數(shù)據(jù)鏈路層(這一層傳輸?shù)臄?shù)據(jù)要求,必須要有目標mac地址,因為數(shù)據(jù)鏈路層是基于mac地址做數(shù)據(jù)傳輸?shù)模?/p>
那數(shù)據(jù)包中都需要哪些字段呢?如下:
src ip = 192.168.1.2 //源ip地址,交換機
dst ip = 192.168.1.3 //目標ip地址
//本機的mac地址(保證從主機B回來的包正常送達主機A,且主機A能正常處理它)
src mac = 主機A的mac地址
dst mac = 主機B的mac地址//目標mac地址
其中的dst ip
好說,我們可以直接固定寫,或者通過DNS解析域名得到目標ip。
那dst mac
怎么獲取呢?
這就不得不說ARP
協(xié)議了! ARP
其實是一種地址解析協(xié)議,它的作用就是:以目標ip為線索,找到目的ip所在機器的mac地址。也就是幫我們找到dst mac
地址!大概的過程如下幾個step:
簡述這個過程:主機A想給主機B發(fā)包,那需要知道主機B的mac地址。
dst ip
和dst mac
地址的映射關系了,如果已存在,那就直接用。dst ip
和dst mac
地址的映射關系的話那就只能廣播arp請求包,同一網(wǎng)段的所有機器都能收到arp請求包。src ip
是否是自己的ip,如果不是則直接丟棄該arp包。如果是的話就將自己的mac地址寫到arp響應包中。并且它會把請求包中src ip
和src mac
的映射關系存儲在自己的本地。補充:
交換機本身也有學習能力,他會記錄mac地址和交換機端口的映射關系。比如:mac=a,端口為1。
那當它接收到數(shù)據(jù)包,并發(fā)現(xiàn)mac=a時,它會直接將數(shù)據(jù)扔向端口1。
當然,也可以看下維基百科中列舉的同局域網(wǎng)中兩臺computer互聯(lián)的簡單例子:
再看下linux操作系統(tǒng)中的arp命令:
# 發(fā)送一個arp廣播,如下:
~]# arp -a
gateway (192.168.0.1) at fa:16:3e:66:c8:15 [ether] on eth0
? (192.168.0.254) at fa:fa:fa:fa:fa:01 [ether] on eth0
# 可以看到網(wǎng)關ip地址:192.168.0.1,mac地址是:fa:16:3e:66:c8:15 網(wǎng)卡是eth0
# 廣播地址:192.168.0.254,mac地址是:fa:fa:fa:fa:fa:01 網(wǎng)卡是eth0
嗯,在arp協(xié)議的幫助下,主機A順利拿到了主機B的mac地址。于是數(shù)據(jù)包從網(wǎng)絡層流轉(zhuǎn)到數(shù)據(jù)鏈路層時已經(jīng)被封裝成了下面的樣子:
src ip = 192.168.1.2
src mac = 主機A的mac地址
dst ip = 192.168.1.3
dst mac = 主機B的mac地址
網(wǎng)絡層基于ip地址做數(shù)據(jù)做轉(zhuǎn)發(fā)
數(shù)據(jù)鏈路基于mac地址做數(shù)據(jù)轉(zhuǎn)發(fā)
根據(jù)OIS7層網(wǎng)絡模型,我們都知道數(shù)據(jù)包經(jīng)過物理層發(fā)送到機器B,機器B接收到數(shù)據(jù)包后,再將數(shù)據(jù)包向上流轉(zhuǎn),拆包。流轉(zhuǎn)到主機B的數(shù)據(jù)鏈路層。
那主機B是如何判斷這個在數(shù)據(jù)鏈路層的包是否是發(fā)給自己的呢?答案前面說了,根據(jù)目的mac地址判斷。
// 主機B
if 收到的數(shù)據(jù)包.MAC地址 == 自己的MAC地址{
if dst ip == 本機ip{
// 本地處理數(shù)據(jù)包
}else{
// 查詢路由表,根據(jù)路由表的規(guī)則,將數(shù)據(jù)包轉(zhuǎn)某個某卡、或者默認網(wǎng)關
}
}else{
// 直接丟棄
}
這個例子比較簡單,dst ip
就是主機B的本機ip
所以它自己會處理這個數(shù)據(jù)包。
那數(shù)據(jù)包處理完之后是需要給主機A一個響應包,那問題又來了,響應包該封裝成什么樣子呢?對主機B來說響應包也需要src ip
、src mac
、dst ip
、dst mac
src ip = 192.168.1.3
src mac = 主機B的mac地址
dst ip = 192.168.1.2
src mac = 主機A的mac地址 (之前通過arp記錄在自己的arp高速緩存中了,所以,這次直接用)
同樣的道理,響應包也會按照如下的邏輯被主機A接受,處理。
// 主機A
if 收到的數(shù)據(jù)包.MAC地址 == 自己的MAC地址{
if dst ip == 本機ip{
// 本地處理數(shù)據(jù)包
}else{
// 查詢路由表,根據(jù)路由表的規(guī)則,將數(shù)據(jù)包轉(zhuǎn)某個某卡、或者默認網(wǎng)關
}
}else{
// 直接丟棄
}
然后再補充一點,我們可以通過下面的命令查看路由轉(zhuǎn)發(fā)是否開啟:
~]# cat /proc/sys/net/ipv4/ip_forward
1
嗯,同一個局域網(wǎng)中的不同主機的通信方式大概就是這樣子。下面我們再來看一下跨網(wǎng)段的不同主機的互聯(lián)原理。
通過上面的描述,如下這張圖描述同一個局域網(wǎng)內(nèi)的不同主機192.168.1.3
和192.168.1.2
互聯(lián)的原理大家已經(jīng)很清楚了。
那不同網(wǎng)段的主機之間是如何互聯(lián)的呢?
或者說,當你訪問:www.baidu.com 時,都發(fā)生了什么?你的請求是如何打到百度的服務器機房里面去的?
那,我們先嘗試ping一下百度,如下,可以看到百度服務對外暴露的ip地址是220.181.38.148
~ % ping baidu.com
PING baidu.com (220.181.38.148): 56 data bytes
64 bytes from 220.181.38.148: icmp_seq=0 ttl=48 time=38.812 ms
64 bytes from 220.181.38.148: icmp_seq=1 ttl=48 time=38.944 ms
64 bytes from 220.181.38.148: icmp_seq=2 ttl=48 time=23.507 ms
64 bytes from 220.181.38.148: icmp_seq=3 ttl=48 time=33.429 ms
^C
--- baidu.com ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 23.507/33.673/38.944/6.277 ms
那,再通過ifconfig
命令看下我的本機ip地址是192.168.0.64
像這種192.168.xx.xx這種局域網(wǎng)機器的ip通常使用dhcp動態(tài)分配
我們也可以設置手動設置靜態(tài)ip
比如可以通過如下命令設置eth0網(wǎng)卡信息
vi /etc/sysconfig/network-scripts/ifcfg-eth0
那,另外我的機器還有運營商分配的公網(wǎng)ip地址:121.36.30.75
有了上面這些信息,于是我們就能畫出下面這張圖:
然后我們再看一下當我們使用192.168.0.64
訪問百度時,數(shù)據(jù)包是如何被一層層轉(zhuǎn)發(fā)到百度的IDC機房的,然后我電腦又是如何處理百度的回包的!
對我的機器來說,我想訪問百度的服務器,也就是往百度的服務器發(fā)數(shù)據(jù)包的話,那我的電腦得先封裝好數(shù)據(jù)包吧!
那數(shù)據(jù)包里面起碼要包含哪些信息呢?其實在上面的第一節(jié)中我們已經(jīng)說過了,也就是src ip
、src mac
、dst ip
、dst mac
對于我的電腦來說:
src ip = 192.168.0.64
src mac = fa:16:3e:6b:ab:64 (本機mac地址)
dst ip = 220.181.38.251 (通過DNS服務解析www.baidu.com獲取到)
dst mac = ???
那dst mac
目的mac地址是多少呢?這是個問題!
因為我是192.168.0.X
網(wǎng)段,百度的服務器在220.181.38.X
網(wǎng)段,我們都不在一個網(wǎng)段中!我的機器沒法直接獲取到百度對外暴露的網(wǎng)關的mac地址。
那怎么我的機器怎么辦呢?
答案是:我的機器會先查看一下自己的路由表,路由表會記錄該將這個數(shù)據(jù)包轉(zhuǎn)發(fā)到哪里去。具體可通過route -n
命令可以查看到,如下:
具體的做法就是,拿著dst ip 220.181.38.251
,分別和路由表中的Genmask做與操作,ip地址 與 子網(wǎng)掩碼可以得到該ip地址所在的網(wǎng)段,那得到了dst ip
所在的網(wǎng)段之后呢,就拿著這個網(wǎng)段和路由表中的Destination
對比,如果相同的話,就將數(shù)據(jù)包準發(fā)給他。
在我們這個例子中,很明顯dst ip 220.181.38.251
跟后三條路由相與得到的結(jié)果和route表期望的Destination
都不匹配。
但是dst ip 220.181.38.251
跟第一條路由表中的記錄相與,得到的結(jié)果肯定符合route預期的Destination
,畢竟誰與0,結(jié)果都是0嘛。(它的Flags為UG,表示它就是網(wǎng)關,也就是網(wǎng)絡的出口)
找到了符合預期的路由后,我的機器就會先將數(shù)據(jù)包發(fā)送給網(wǎng)關,對應的網(wǎng)卡就是eth0
,那這也就意味著我們找到了第一個跳目的ethernet地址。于是數(shù)據(jù)包被封裝成下面這樣
src ip = 192.168.0.64
src mac = fa:16:3e:6b:ab:64 (本機mac地址)
dst ip = 220.181.38.251 (通過DNS服務解析www.baidu.com獲取到)
dst mac = eth0網(wǎng)卡的mac地址。(ip地址是:192.168.0.1)
同樣的道理,當eth0網(wǎng)卡收到這個數(shù)據(jù)包后,路由器進行如下的判斷。
if 數(shù)據(jù)包.mac == 自己的mac{
// mac地址相同,說明這是發(fā)送給自己的包,所以它不會丟棄。
if 數(shù)據(jù)包.ip == 自己的ip{
// 說明這就是發(fā)給他的數(shù)據(jù)包,但是它只是一個路由器,只有OSI7層網(wǎng)絡中的前三層。所以他的將數(shù)據(jù)包發(fā)給其他設備
}else{
// 繼續(xù)查看自己的路由表,找到合適的下一跳地址(扔給網(wǎng)關)。
}
}else{
// 直接丟棄
}
經(jīng)過上面?zhèn)未a的判斷,eth0知道了這個包雖然是發(fā)給它的,但它并不能繼續(xù)處理這個數(shù)據(jù)包,他需要將這個數(shù)據(jù)包準發(fā)給下一跳。
對它現(xiàn)在來說:
src ip = 192.168.0.1 (上圖LAN口的ip地址)
src mac = eth0的mac地址,
dst ip = 220.181.38.251
dst mac = ???
那dst mac
地址怎么獲取到呢?其實和上面的流程類似,需要查詢路由表。使用src ip
和路由表中的子網(wǎng)掩碼相與,得到網(wǎng)段后再與Desitantion
對比。由于這個路由器上確實沒有連接220.180.38.xxx
的網(wǎng)段,所以數(shù)據(jù)包最終依然會被轉(zhuǎn)發(fā)到這個路由器的公網(wǎng)網(wǎng)關。
經(jīng)過這一步,數(shù)據(jù)包流轉(zhuǎn)到路由器的WAN口,再往下走就流入公網(wǎng)啦!
數(shù)據(jù)包在公網(wǎng)中各個路由節(jié)點之間跳轉(zhuǎn),最終會流轉(zhuǎn)到百度對外暴露的網(wǎng)關路由器的公網(wǎng)WAN口。
然后數(shù)據(jù)包會從這個WAN口流入百度內(nèi)網(wǎng)的IDC機房集群。
你可能會問:那這次請求會打向百度IDC機房中的那臺機器呢?
嗯,這就沒法再展開了,百度肯定會有他自己的負載均衡機制。我們只需知道這個數(shù)據(jù)包最終肯定會流轉(zhuǎn)到某一臺具體的物理器、或者是某個容器內(nèi)就好啦!
這就要講到NAT技術(shù)了,看下面的這張圖:
數(shù)據(jù)包傳輸出去的過程中,雖然dst ip
始終都是百度對外暴露公網(wǎng)網(wǎng)關的ip地址,但是src ip
卻一直不斷的被改變。從一開始的192.168.0.64
=>192.168.0.1
=> 121.36.30.75
---------------我的機器------------
=> src ip = 192.168.0.64 ....
---------------我的機器------------
---------------路由器----------------
然后=> src ip = 192.168.0.1 .... (路由器的LAN口)
然后=> src ip = 121.36.30.75 ....(路由器的WAN口)
---------------路由器----------------
在數(shù)據(jù)包在被發(fā)送到公網(wǎng)之前會被路由器做一次SNAT
處理,全稱是:source network address translator
源網(wǎng)絡地址轉(zhuǎn)換,它的目的就是將私網(wǎng)ip轉(zhuǎn)換成路由器的公網(wǎng)ip。
當然了,路由器也都會記錄下SNAT
轉(zhuǎn)換前和轉(zhuǎn)換后的狀態(tài)。畢竟如果不出意外話,路由器總能接受到百度給他的回包,但他是不能解析處理這個數(shù)據(jù)包的。(只有請求的發(fā)送者192.168.0.64
這臺機器的應用層才能正確解析出這個響應包)。所以路由器需要根據(jù)轉(zhuǎn)發(fā)記錄將這個包轉(zhuǎn)發(fā)給我們起初發(fā)送請求的機器(也就是192.168.0.64
)。
而這些記錄會被路由器記錄在它的地址轉(zhuǎn)換表中。
如下:
看上圖中綠色的部分,在地址轉(zhuǎn)換表中記錄,數(shù)據(jù)包的原地址從192.168.0.64:1234
被轉(zhuǎn)成了121.36.30.75:1234
。(這種帶端口號的地址轉(zhuǎn)換其實叫NAPT
)
那我們繼續(xù)往下看,假如我們的路由器收到百度的響應包長下面這樣:
src ip = 220.181.38.251 (百度公網(wǎng)網(wǎng)關路由器WAN口ip地址)
src mac = 百度公網(wǎng)網(wǎng)關路由器的mac地址
dst ip = 121.36.30.75:1234 (我們家里路由器的WAN口ip地址)
dst mac = 我們家里路由器的mac地址
同樣的道理,我們家里路由器會有下面?zhèn)未a的判斷邏輯。
if 響應包.mac == 自己的mac{
// 說明這是發(fā)給自己包,所以不能丟棄
if 響應包.ip == 自己的ip{
// 哎?ip也是自己的ip!
// 但是它只是一個路由器,只有OSI7層網(wǎng)絡模型的前三層
// 所以路由器并不能真正的處理解析這個數(shù)據(jù)包,只能根據(jù)NAT表繼續(xù)轉(zhuǎn)發(fā)
if 地址轉(zhuǎn)換表.Contains(響應包.dstIp){
// 通過查地址轉(zhuǎn)換表發(fā)現(xiàn):
// dst ip = 121.36.30.75:1234 的流量,需要轉(zhuǎn)給:192.168.0.64:1234
// 轉(zhuǎn)發(fā)...
}
}else{
// 查自己的route表,找下一跳
}
}else{
// 直接丟棄
}
這樣的話,我們的發(fā)送請求的機器就接收到百度的響應包了,響應數(shù)據(jù)再一路往OIS7層網(wǎng)絡模型的上層傳遞,最后到應用層根據(jù)http協(xié)議解析出響應報文,經(jīng)過瀏覽器渲染html報文,于是下面的網(wǎng)頁就展現(xiàn)在了我們面前!