为什么我在公司里访问不了家里的电脑
上篇文章「為什么我們家里的 IP 都是 192.168 開頭的?」提到,因?yàn)?IPv4 地址有限,最大 42 億個(gè)。為了更好的利用這有限的 IP 數(shù)量,網(wǎng)絡(luò)分為局域網(wǎng)和廣域網(wǎng),將 IP 分為了私有 IP 和公網(wǎng) IP,一個(gè)局域網(wǎng)里的 N 多臺(tái)機(jī)器都可以共用一個(gè)公網(wǎng) IP,從而大大增加了 "可用 IP 數(shù)量"。
當(dāng)我們需要發(fā)送網(wǎng)絡(luò)包的時(shí)候,在 IP 層,需要填入源 IP 地址,和目的 IP 地址,也就是對(duì)應(yīng)快遞的發(fā)貨地址和收貨地址。
但是我們家里的局域網(wǎng)內(nèi),基本上都用 192.168.xx.xx 這樣的私有 IP。
如果我們?cè)诎l(fā)送網(wǎng)絡(luò)包的時(shí)候,這么填。對(duì)方在回?cái)?shù)據(jù)包的時(shí)候該怎么回?畢竟千家萬(wàn)戶人用的都是 192.168.0.1,網(wǎng)絡(luò)怎么知道該發(fā)給誰(shuí)?
所以肯定需要將這個(gè) 192.168.xx 私有 IP 轉(zhuǎn)換成公有 IP。
因此在上篇文章最后,留了這么個(gè)問(wèn)題。局域網(wǎng)內(nèi)用的是私有 IP,公網(wǎng)用的都是公有 IP。一個(gè)局域網(wǎng)里的私有 IP 想訪問(wèn)局域網(wǎng)外的公有 IP,必然要做個(gè) IP 轉(zhuǎn)換,這是在哪里做的轉(zhuǎn)換呢?
答案是 NAT 設(shè)備,全稱 NetworkAddressTranslation,網(wǎng)絡(luò)地址轉(zhuǎn)換。基本上家用路由器都支持這功能。
我們來(lái)聊下它是怎么工作的。
NAT 的工作原理
為了簡(jiǎn)單,我們假設(shè)你很富,你家里分到了一個(gè)公網(wǎng) IP 地址20.20.20.20,對(duì)應(yīng)配到了你家自帶 NAT 功能的家用路由器上,你家里需要上網(wǎng)的設(shè)備有很多,比如你的手機(jī),電腦都需要上網(wǎng),他們構(gòu)成了一個(gè)局域網(wǎng),用的都是私有 IP,比如 192.168.xx。其中你在電腦上執(zhí)行 ifconfig 命令,發(fā)現(xiàn)家里的電腦 IP 是 192.168.30.5。你要訪問(wèn)的公網(wǎng) IP 地址是 30.30.30.30。
于是就有下面這樣一張圖
當(dāng)你準(zhǔn)備發(fā)送數(shù)據(jù)包的時(shí)候,你的電腦內(nèi)核協(xié)議棧就會(huì)構(gòu)造一個(gè) IP 數(shù)據(jù)包。這個(gè) IP 數(shù)據(jù)包報(bào)頭里的發(fā)送端 IP 地址填的就是 192.168.30.5,接收端 IP 地址就是 30.30.30.30。將數(shù)據(jù)包發(fā)到 NAT 路由器中。
此時(shí) NAT 路由器會(huì)將 IP 數(shù)據(jù)包里的源 IP 地址修改一下,私有 IP 地址 192.168.30.5 改寫為公網(wǎng) IP 地址 20.20.20.20,這叫 SNAT(SourceNetworkAddressTranslation,源地址轉(zhuǎn)換)。并且還會(huì)在 NAT 路由器內(nèi)部留下一條192.168.30.5 -> 20.20.20.20 的映射記錄,這個(gè)信息會(huì)在后面用到。之后 IP 數(shù)據(jù)包經(jīng)過(guò)公網(wǎng)里各個(gè)路由器的轉(zhuǎn)發(fā),發(fā)到了接收端 30.30.30.30,到這里發(fā)送流程結(jié)束。
如果接收端處理完數(shù)據(jù)了,需要發(fā)一個(gè)響應(yīng)給你的電腦,那就需要將發(fā)送端 IP 地址填上自己的 30.30.30.30,將接收端地址填為你的公網(wǎng) IP 地址 20.20.20.20,發(fā)往 NAT 路由器。NAT 路由器收到公網(wǎng)來(lái)的消息之后,會(huì)檢查下自己之前留下的映射信息,發(fā)現(xiàn)之前留下了這么一條192.168.30.5 -> 20.20.20.20 記錄,就會(huì)將這個(gè)數(shù)據(jù)包的目的 IP 地址修改一下,變成內(nèi)網(wǎng) IP 地址 192.168.30.5, 這也叫 DNAT(DestinationNetworkAddressTranslation,目的地址轉(zhuǎn)換)。之后將其轉(zhuǎn)發(fā)給你的電腦上。
整個(gè)過(guò)程下來(lái),NAT 悄悄的改了 IP 數(shù)據(jù)包的發(fā)送和接收端 IP 地址,但對(duì)真正的發(fā)送方和接收方來(lái)說(shuō),他們卻對(duì)這件事情,一無(wú)所知。
這就是 NAT 的工作原理。
NAPT 的原理
到這里,相信大家都有一個(gè)很大的疑問(wèn)。
局域網(wǎng)里并不只有一臺(tái)機(jī)器,局域網(wǎng)內(nèi) 每臺(tái)機(jī)器都在 NAT 下留下的映射信息都會(huì)是192.168.xx.xx -> 20.20.20.20,發(fā)送消息是沒啥事,但接收消息的時(shí)候就不知道該回給誰(shuí)了。
這問(wèn)題相當(dāng)致命,因此實(shí)際上大部分時(shí)候不會(huì)使用普通的 NAT。
那怎么辦呢?
問(wèn)題出在我們沒辦法區(qū)分內(nèi)網(wǎng)里的多個(gè)網(wǎng)絡(luò)連接。
于是乎。
我們可以加入其他信息去區(qū)分內(nèi)網(wǎng)里的各個(gè)網(wǎng)絡(luò)連接,很自然就能想到端口。
但 IP 數(shù)據(jù)包(網(wǎng)絡(luò)層)本身是沒有端口信息的。常見的傳輸層協(xié)議 TCP 和 UDP 數(shù)據(jù)報(bào)文里才有端口的信息。
于是流程就變成了下面這樣子。
當(dāng)你準(zhǔn)備發(fā)送數(shù)據(jù)包的時(shí)候,你的電腦內(nèi)核協(xié)議棧就會(huì)先構(gòu)造一個(gè) TCP 或者 UDP 數(shù)據(jù)報(bào)頭,里面寫入端口號(hào),比如發(fā)送端口是 5000,接收端口是 3000,然后在這個(gè)基礎(chǔ)上,加入 IP 數(shù)據(jù)報(bào)頭,填入發(fā)送端和接收端的 IP 地址。
那數(shù)據(jù)包長(zhǎng)這樣。
假設(shè),發(fā)送端 IP 地址填的就是 192.168.30.5,接收端 IP 地址就是 30.30.30.30。
將數(shù)據(jù)包發(fā)到 NAT 路由器中。
此時(shí) NAT 路由器會(huì)將 IP 數(shù)據(jù)包里的源 IP 地址和端口號(hào)修改一下,從 192.168.30.5:5000 改寫成 20.20.20.20:6000。并且還會(huì)在 NAT 路由器內(nèi)部留下一條192.168.30.5:5000 -> 20.20.20.20:6000 的映射記錄。之后數(shù)據(jù)包經(jīng)過(guò)公網(wǎng)里各個(gè)路由器的轉(zhuǎn)發(fā),發(fā)到了接收端 30.30.30.30:3000,到這里發(fā)送流程結(jié)束。
接收端響應(yīng)時(shí),就會(huì)在數(shù)據(jù)包里填入發(fā)送端地址是 30.30.30.30:3000,將接收端是 20.20.20.20:6000,發(fā)往 NAT 路由器。NAT 路由器發(fā)現(xiàn)下自己之前留下過(guò)這么一條192.168.30.5:5000 -> 20.20.20.20:6000 的記錄,就會(huì)將這個(gè)數(shù)據(jù)包的目的 IP 地址和端口修改一下,變回原來(lái)的 192.168.30.5:5000。之后將其轉(zhuǎn)發(fā)給你的電腦上。
如果局域網(wǎng)內(nèi)有多個(gè)設(shè)備,他們就會(huì)映射到不同的公網(wǎng)端口上,畢竟端口最大可達(dá) 65535,完全夠用。這樣大家都可以相安無(wú)事。
像這種同時(shí)轉(zhuǎn)換 IP 和端口的技術(shù),就是 NAPT(Network Address Port Transfer ,網(wǎng)絡(luò)地址端口轉(zhuǎn)換)。
看到這里,問(wèn)題就來(lái)了。
那這么說(shuō)只有用到端口的網(wǎng)絡(luò)協(xié)議才能被 NAT 識(shí)別出來(lái)并轉(zhuǎn)發(fā)?
但這怎么解釋 ping 命令?ping 基于 ICMP 協(xié)議,而 ICMP 協(xié)議報(bào)文里并不帶端口信息。我依然可以正常的 ping 通公網(wǎng)機(jī)器并收到回包。
事實(shí)上針對(duì) ICMP 協(xié)議,NAT 路由器做了特殊處理。ping 報(bào)文頭里有個(gè) Identifier 的信息,它其實(shí)指的是放出 ping 命令的進(jìn)程 id。
對(duì) NAT 路由器來(lái)說(shuō),這個(gè) Identifier 的作用就跟端口一樣。
另外,當(dāng)我們?nèi)プグ臅r(shí)候,就會(huì)發(fā)現(xiàn)有兩個(gè) Identifier,一個(gè)后面帶個(gè) BE(Big Endian),另一個(gè)帶個(gè) LE(Little Endian)。
其實(shí)他們都是同一個(gè)數(shù)值,只不過(guò)大小端不同,讀出來(lái)的值不一樣。就好像同樣的數(shù)字 345,反著讀就成了 543。這是為了兼容不同操作系統(tǒng)(比如 linux 和 Windows)下大小端不同的情況。
內(nèi)網(wǎng)穿透是什么
看到這里,我們大概也發(fā)現(xiàn)了。使用了 NAT 上網(wǎng)的話,前提得內(nèi)網(wǎng)機(jī)器主動(dòng)請(qǐng)求公網(wǎng) IP,這樣 NAT 才能將內(nèi)網(wǎng)的 IP 端口轉(zhuǎn)成外網(wǎng) IP 端口。
反過(guò)來(lái)公網(wǎng)的機(jī)器想主動(dòng)請(qǐng)求內(nèi)網(wǎng)機(jī)器,就會(huì)被攔在 NAT 路由器上,此時(shí)由于 NAT 路由器并沒有任何相關(guān)的 IP 端口的映射記錄,因此也就不會(huì)轉(zhuǎn)發(fā)數(shù)據(jù)給內(nèi)網(wǎng)里的任何一臺(tái)機(jī)器。
舉個(gè)現(xiàn)實(shí)中的場(chǎng)景就是,你在你家里的電腦上啟動(dòng)了一個(gè) HTTP 服務(wù),地址是 192.168.30.5:5000,此時(shí)你在公司辦公室里想通過(guò)手機(jī)去訪問(wèn)一下,卻發(fā)現(xiàn)訪問(wèn)不了。
那問(wèn)題就來(lái)了,有沒有辦法讓外網(wǎng)機(jī)器訪問(wèn)到內(nèi)網(wǎng)的服務(wù)?
有。
大家應(yīng)該聽過(guò)一句話叫," 沒有什么是加中間層不能解決的,如果有,那就再加一層 "。
放在這里,依然適用。
說(shuō)到底,因?yàn)?NAT 的存在,我們只能從內(nèi)網(wǎng)主動(dòng)發(fā)起連接,否則 NAT 設(shè)備不會(huì)記錄相應(yīng)的映射關(guān)系,沒有映射關(guān)系也就不能轉(zhuǎn)發(fā)數(shù)據(jù)。
所以我們就在公網(wǎng)上加一臺(tái)服務(wù)器 x,并暴露一個(gè)訪問(wèn)域名,再讓內(nèi)網(wǎng)的服務(wù)主動(dòng)連接服務(wù)器 x,這樣 NAT 路由器上就有對(duì)應(yīng)的映射關(guān)系。接著,所有人都去訪問(wèn)服務(wù)器 x,服務(wù)器 x 將數(shù)據(jù)轉(zhuǎn)發(fā)給內(nèi)網(wǎng)機(jī)器,再原路返回響應(yīng),這樣數(shù)據(jù)就都通了。這就是所謂的內(nèi)網(wǎng)穿透。
像上面提到的服務(wù)器 x,你也不需要自己去搭,已經(jīng)有很多現(xiàn)成的方案,花錢就完事了,比如花某殼。
到這里,我們就可以回答文章標(biāo)題的問(wèn)題。
為什么我在公司里訪問(wèn)不了家里的電腦?
那是因?yàn)榧依锏碾娔X在局域網(wǎng)內(nèi),局域網(wǎng)和廣域網(wǎng)之間有個(gè) NAT 路由器。由于 NAT 路由器的存在,外網(wǎng)服務(wù)無(wú)法主動(dòng)連通局域網(wǎng)內(nèi)的電腦。
兩個(gè)內(nèi)網(wǎng)的聊天軟件如何建立通訊
好了,問(wèn)題就叒來(lái)了。
我家機(jī)子是在我們小區(qū)的局域網(wǎng)里,班花家的機(jī)子也是在她們小區(qū)的局域網(wǎng)里。都在局域網(wǎng)里,且 NAT 只能從內(nèi)網(wǎng)連到外網(wǎng),那我電腦上登錄的 QQ 是怎么和班花電腦里的 QQ 連上的呢?
上面這個(gè)問(wèn)法其實(shí)是存在個(gè)誤解,誤以為兩個(gè) qq 客戶端應(yīng)用是直接建立連接的。
然而實(shí)際上并不是,兩個(gè) qq 客戶端之間還隔了一個(gè)服務(wù)器。
也就是說(shuō),兩個(gè)在內(nèi)網(wǎng)的客戶端登錄 qq 時(shí)都會(huì)主動(dòng)向公網(wǎng)的聊天服務(wù)器建立連接,這時(shí)兩方的 NAT 路由器中都會(huì)記錄有相應(yīng)的映射關(guān)系。當(dāng)在其中一個(gè) qq 上發(fā)送消息時(shí),數(shù)據(jù)會(huì)先到服務(wù)器,再通過(guò)服務(wù)器轉(zhuǎn)發(fā)到另外一個(gè)客戶端上。反過(guò)來(lái)也一樣,通過(guò)這個(gè)方式讓兩臺(tái)內(nèi)網(wǎng)的機(jī)子進(jìn)行數(shù)據(jù)傳輸。
兩個(gè)內(nèi)網(wǎng)的應(yīng)用如何直接建立連接
上面的情況,是兩個(gè)客戶端通過(guò)第三方服務(wù)器進(jìn)行通訊,但有些場(chǎng)景就是要拋開第三端,直接進(jìn)行兩端通信,比如 P2P 下載,這種該怎么辦呢?
這種情況下,其實(shí)也還是離不開第三方服務(wù)器的幫助。
假設(shè)還是 A 和 B 兩個(gè)局域網(wǎng)內(nèi)的機(jī)子,A 內(nèi)網(wǎng)對(duì)應(yīng)的 NAT 設(shè)備叫 NAT_A,B 內(nèi)網(wǎng)里的 NAT 設(shè)備叫 NAT_B,和一個(gè)第三方服務(wù)器 server。
流程如下。
step1 和 2: A 主動(dòng)去連 server,此時(shí) A 對(duì)應(yīng)的 NAT_A 就會(huì)留下 A 的內(nèi)網(wǎng)地址和外網(wǎng)地址的映射關(guān)系,server 也拿到了 A 對(duì)應(yīng)的外網(wǎng) IP 地址和端口。
step3 和 4: B 的操作和 A 一樣,主動(dòng)連第三方 server,NAT_B 內(nèi)留下 B 的內(nèi)網(wǎng)地址和外網(wǎng)地址的映射關(guān)系,然后 server 也拿到了 B 對(duì)應(yīng)的外網(wǎng) IP 地址和端口。
step5 和 step6 以及 step7: 重點(diǎn)來(lái)了。此時(shí) server 發(fā)消息給 A,讓 A 主動(dòng)發(fā) UDP 消息到 B 的外網(wǎng) IP 地址和端口。此時(shí) NAT_B 收到這個(gè) A 的 UDP 數(shù)據(jù)包時(shí),這時(shí)候根據(jù) NAT_B 的設(shè)置不同,導(dǎo)致這時(shí)候有可能 NAT_B 能直接轉(zhuǎn)發(fā)數(shù)據(jù)到 B,那此時(shí) A 和 B 就通了。但也有可能不通,直接丟包,不過(guò)丟包沒關(guān)系,這個(gè)操作的目的是給 NAT_A 上留下有關(guān) B 的映射關(guān)系。
step8 和 step9 以及 step10: 跟 step5 一樣熟悉的配方,此時(shí) server 再發(fā)消息給 B,讓 B 主動(dòng)發(fā) UDP 消息到 A 的外網(wǎng) IP 地址和端口。NAT_B 上也留下了關(guān)于 A 到映射關(guān)系,這時(shí)候由于之前 NAT_A 上有過(guò)關(guān)于 B 的映射關(guān)系,此時(shí) NAT_A 就能正常接受 B 的數(shù)據(jù)包,并將其轉(zhuǎn)發(fā)給 A。到這里 A 和 B 就能正常進(jìn)行數(shù)據(jù)通信了。這就是所謂的 NAT 打洞。
step11: 注意,之前我們都是用的 UDP 數(shù)據(jù)包,目的只是為了在兩個(gè)局域網(wǎng)的 NAT 上打個(gè)洞出來(lái),實(shí)際上大部分應(yīng)用用的都是 TCP 連接,所以,這時(shí)候我們還需要在 A 主動(dòng)向 B 發(fā)起 TCP 連接。到此,我們就完成了兩端之間的通信。
這里估計(jì)大家會(huì)有疑惑。
端口已經(jīng)被 udp 用過(guò)了,TCP 再用,那豈不是端口重復(fù)占用(address already in use)?
其實(shí)并不會(huì),端口重復(fù)占用的報(bào)錯(cuò)常見于兩個(gè) TCP 連接在不使用 SO_REUSEADDR 的情況下,重復(fù)使用了某個(gè) IP 端口。而 UDP 和 TCP 之間卻不會(huì)報(bào)這個(gè)錯(cuò)。之所以會(huì)有這個(gè)錯(cuò),主要是因?yàn)樵谝粋€(gè) linux 內(nèi)核中,內(nèi)核收到網(wǎng)絡(luò)數(shù)據(jù)時(shí),會(huì)通過(guò)五元組(傳輸協(xié)議,源 IP,目的 IP,源端口,目的端口)去唯一確定數(shù)據(jù)接受者。當(dāng)五元組都一模一樣的時(shí)候,內(nèi)核就不知道該把數(shù)據(jù)發(fā)給誰(shuí)。而 UDP 和 TCP 之間 "傳輸協(xié)議" 不同,因此五元組也不同,所以也就不會(huì)有上面的問(wèn)題。
NAPT 還分為好多種類型,上面的 nat 打洞方案,都能成功嗎?
關(guān)于 NAPT,確實(shí)還細(xì)分為好幾種類型,比如完全錐形 NAT 和限制型 NAT 啥的,但這并不是本文的重點(diǎn)。所以我就略過(guò)了。我們現(xiàn)在常見的都是錐形 NAT。上面的打洞方案適用于大部分場(chǎng)景,這其中包括限制最多的端口受限錐形 NAT。
總結(jié)
?IPV4 地址有限,但通過(guò) NAT 路由器,可以使得整個(gè)內(nèi)網(wǎng) N 多臺(tái)機(jī)器,對(duì)外只使用一個(gè)公網(wǎng) IP,大大節(jié)省了 IP 資源。
?內(nèi)網(wǎng)機(jī)子主動(dòng)連接公網(wǎng) IP,中間的 NAT 會(huì)將內(nèi)網(wǎng)機(jī)子的內(nèi)網(wǎng) IP 轉(zhuǎn)換為公網(wǎng) IP,從而實(shí)現(xiàn)內(nèi)網(wǎng)和外網(wǎng)的數(shù)據(jù)交互。
?普通的 NAT 技術(shù),只會(huì)修改網(wǎng)絡(luò)包中的發(fā)送端和接收端 IP 地址,當(dāng)內(nèi)網(wǎng)設(shè)備較多時(shí),將有可能導(dǎo)致沖突。因此一般都會(huì)使用 NAPT 技術(shù),同時(shí)修改發(fā)送端和接收端的 IP 地址和端口。
?由于 NAT 的存在,公網(wǎng) IP 是無(wú)法訪問(wèn)內(nèi)網(wǎng)服務(wù)的,但通過(guò)內(nèi)網(wǎng)穿透技術(shù),就可以讓公網(wǎng) IP 訪問(wèn)內(nèi)網(wǎng)服務(wù)。一波操作下來(lái),就可以在公司的網(wǎng)絡(luò)里訪問(wèn)家里的電腦。
最后留個(gè)問(wèn)題,有了 NAT 之后,原本并不富裕的 IPv4 地址突然就變得非常夠用了。
那我們?yōu)槭裁催€需要 IPv6?
另外 IPv6 號(hào)稱地址多到每粒沙子都能擁有自己的 IP 地址,那我們還需要 NAT 嗎?
本文來(lái)自微信公眾號(hào):小白 debug (ID:xiaobaidebug),作者:小白
總結(jié)
以上是生活随笔為你收集整理的为什么我在公司里访问不了家里的电脑的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: iPhone 15没戏!苹果自研5G芯片
- 下一篇: 单片机小白学步系列(六) 单片机最小系统