p2p之NAT穿透

什么是NAT

NAT(Network Address Translation),網(wǎng)絡(luò)地址轉(zhuǎn)換。是1994年提出的。當(dāng)在專用網(wǎng)內(nèi)部的一些主機(jī)本來已經(jīng)分配到了本地IP地址(即僅在本專用網(wǎng)內(nèi)使用的專用地址),但現(xiàn)在又想和因特網(wǎng)上的主機(jī)通信(并不需要加密)時(shí),可使用NAT方法。
。裝有NAT軟件的路由器叫做NAT路由器,它至少有一個(gè)有效的外部全球IP地址。這樣,所有使用本地地址的主機(jī)在和外界通信時(shí),都要在NAT路由器上將其本地地址轉(zhuǎn)換成全球IP地址,才能和因特網(wǎng)連接。
同樣還有NAPT,網(wǎng)絡(luò)地址、端口轉(zhuǎn)換?,F(xiàn)在一般穿透規(guī)則就是通過獲取ip、端口來實(shí)現(xiàn)的,重點(diǎn)是實(shí)現(xiàn)穿透,所以以下統(tǒng)稱NAT即可。

為什么要穿透NAT

NAT可以有效的減緩全球IP枯竭的問題。但是同時(shí)NAT也屏蔽了內(nèi)部設(shè)備。

比如在局域網(wǎng)A下有一個(gè)內(nèi)網(wǎng)IP地址為192.168.1.155的設(shè)備A,現(xiàn)在一個(gè)設(shè)備B想要訪問這個(gè)設(shè)備A,根據(jù)設(shè)備B所在網(wǎng)絡(luò)可分為一下情況。

  • 設(shè)備B同在局域網(wǎng)A中:
    設(shè)備B可直接通過設(shè)備內(nèi)網(wǎng)ip 192.168.1.155 地址訪問設(shè)備A;
  • 設(shè)備B在外網(wǎng):
    設(shè)備B無法通過設(shè)備A內(nèi)網(wǎng)訪問設(shè)備A;
  • 設(shè)備B在不同局域網(wǎng)A的局域網(wǎng)B中:
    設(shè)備B在通過ip 192.168.1.155 訪問的時(shí)候可能訪問到局域網(wǎng)B下內(nèi)網(wǎng)IP也為192.168.1.155的設(shè)備C,也可能找不到該ip,但是無法訪問設(shè)備A。

這就是為什么在內(nèi)網(wǎng)建立一個(gè)tcp或者udp服務(wù),內(nèi)網(wǎng)客戶端可以通過ip和端口號(hào)直接通信,而外網(wǎng)卻無法訪問該內(nèi)網(wǎng)建立的服務(wù)。
要實(shí)現(xiàn)p2p(Peer to Peer),首先我們的要知道客戶端ip和端口號(hào),但是通過局域網(wǎng)路由器的NAT轉(zhuǎn)換,生成的外網(wǎng)ip和端口我們無法預(yù)知,這樣我們就無法建立p2p連接。

NAPT轉(zhuǎn)換

如果你還是不明白NAT為什么屏蔽了內(nèi)部設(shè)備,接下來舉個(gè)NAT轉(zhuǎn)換例子就明白了。
例:
內(nèi)網(wǎng)機(jī)器A ip(192.168.1.188) 端口(9999) - 訪問外網(wǎng)目標(biāo)主機(jī)B ip(220.233.28.42) 端口(8888):

1.數(shù)據(jù)包

目的主機(jī):220.233.28.42
目的端口:8888

源主機(jī):192.168.1.188
源端口:9999 (用戶自定義或隨機(jī))

2.地址轉(zhuǎn)換

目的主機(jī):220.233.28.42
目的端口:8888

源主機(jī):123.206.41.242 (NAPT轉(zhuǎn)換,為路由器外網(wǎng)ip)
源端口:17309 (NAPT轉(zhuǎn)換)

3.記錄地址映射

192.168.1.188:9999 ---- 123.206.41.242:17309

4.外網(wǎng)主機(jī)B向內(nèi)網(wǎng)主機(jī)A返回響應(yīng)消息

目的主機(jī):123.206.41.242
目的端口:17309

源主機(jī):220.233.28.42
源端口:8888

5.NAPT查找地址映像并轉(zhuǎn)換

目的主機(jī):192.168.1.188
目的端口:9999

源主機(jī):220.233.28.42
源端口:8888

通過地址轉(zhuǎn)換,主機(jī)A的內(nèi)網(wǎng)地址被映射之后我們是無法預(yù)知的,而且我們無法通過主機(jī)A的內(nèi)網(wǎng)地址直接訪問A,所以NAT屏蔽了主機(jī)A。

通過例子可以看到,當(dāng)主機(jī)A訪問外網(wǎng)主機(jī)B時(shí),通過NAT隨機(jī)分配一個(gè)(外網(wǎng)ip為路由器外網(wǎng)ip)端口,這樣就把內(nèi)網(wǎng)地址映射成了一個(gè)唯一的外網(wǎng)地址。然后外網(wǎng)主機(jī)B響應(yīng)主機(jī)A時(shí),主機(jī)B不直接訪問主機(jī)A,而是通過NAT轉(zhuǎn)換后的地址訪問路由器,路由器就會(huì)通過映射把數(shù)據(jù)分配給內(nèi)網(wǎng)主機(jī)A。這也就是NAT穿透的原理。

NAPT穿透原理

通過雙方所在網(wǎng)絡(luò)環(huán)境不同可分為一下模式:

  • 一個(gè)在局域網(wǎng),另一個(gè)在外網(wǎng)
  • 都在不同的局域網(wǎng)
  • 都在相同的局域網(wǎng)

上一章節(jié)已經(jīng)提到了一種穿透方式,即:局域網(wǎng)-外網(wǎng)的訪問模式,因?yàn)橹鳈C(jī)B在外網(wǎng),ip端口確定,主機(jī)A可以直接通過B的外網(wǎng)地址訪問B,外網(wǎng)主機(jī)B首先接受到了主機(jī)A的數(shù)據(jù)包,便可以知道主機(jī)A經(jīng)過NAT轉(zhuǎn)化后的外網(wǎng)地址,然后就可以進(jìn)行相互通信。
但是如果雙方都在不同的局域網(wǎng),互相都不知道自己的外網(wǎng)地址怎么辦。
這種情況就需要利用一個(gè)擁有唯一IP的中間服務(wù)器S,因?yàn)镾 ip固定并且已知,就讓兩個(gè)設(shè)備都向S發(fā)送數(shù)據(jù)包,S就可以的知道兩個(gè)設(shè)備的公網(wǎng)ip,在設(shè)備p2p通信之前先去服務(wù)器查找對(duì)方的ip、端口,就可以實(shí)現(xiàn)通信。
兩個(gè)設(shè)備同時(shí)處在同一個(gè)局域網(wǎng)下,可以不通過NAT,直接用內(nèi)網(wǎng)ip進(jìn)行通信,這是最節(jié)省帶寬的方式。當(dāng)然,也可以通過第二種,通過S服務(wù)器來得到外網(wǎng)ip端口,這種情況外網(wǎng)的IP是相同的(同一個(gè)路由器),只是分配的端口不同。

發(fā)送數(shù)據(jù)的方式利用UDP,雖然UDP不可靠,但是UDP可以輕松實(shí)現(xiàn)穿透。通過瀏覽各大博客,都沒有找到通過TCP實(shí)現(xiàn)穿透的項(xiàng)目,甚至有人說TCP幾乎不可能實(shí)現(xiàn)穿透(博主初學(xué),還望指點(diǎn))。

使用過UDP的肯定知道,首先創(chuàng)建一個(gè)UDP監(jiān)聽端口,然后可以通過這個(gè)端口發(fā)送和接收數(shù)據(jù)包。NAT會(huì)把這個(gè)監(jiān)聽端口映射為外網(wǎng)ip和端口。我們只需要通過端口發(fā)送數(shù)據(jù)包給服務(wù)器就可以讓服務(wù)器拿到這個(gè)端口信息,然后可以讓其他客戶機(jī)通過這個(gè)端口的信息來發(fā)送數(shù)據(jù)給該端口。

在這里NAPT對(duì)UDP的端口映射(session)還有一定的規(guī)則:

  • A.源地址(內(nèi)網(wǎng)ip)不相同,忽略其他因素,則session不同。
  • B.源地址相同,源端口不同,忽略其他因素,則session不同。
  • C.源地址相同,源端口相同,目標(biāo)地址不同,對(duì)于不同的NAPT,session可能不同。(一般大部分是相同的,不同的無法進(jìn)行穿透)
  • D.源地址相同,源端口相同,目標(biāo)地址相同,任何端口,session一定相同。

session并不是長(zhǎng)期存在的,不同的路由器session儲(chǔ)存時(shí)間不同,短的有的幾十秒,長(zhǎng)的可能有的幾分種。要想維持這個(gè)session可以通過心跳包來維持,比如10秒向服務(wù)器發(fā)送一個(gè)心跳包。并且對(duì)于上面第三種情況,如果最后session不同,就無法實(shí)現(xiàn)穿透(這種類型一般少見)。

NAT穿透UDP具體實(shí)現(xiàn)

本來是打算把我的java代碼黏貼出來的,后來想了想,我寫的只是其中一種實(shí)現(xiàn)方式,不同語言也有不同的實(shí)現(xiàn)方式,我就來說說實(shí)現(xiàn)的步驟,就不再寫代碼了。也挺簡(jiǎn)單的。

  1. 客戶端建立一個(gè)UDP監(jiān)聽端口
  2. 客戶端做一個(gè)心跳包向服務(wù)器發(fā)送數(shù)據(jù)包
  3. 服務(wù)器接收到心跳包后,儲(chǔ)存客戶端的ip、端口信息

當(dāng)客戶端要進(jìn)行p2p通信的時(shí)候

  1. 發(fā)送方服務(wù)器查詢接收方ip、端口
  2. 數(shù)據(jù)包定向ip、端口發(fā)送數(shù)據(jù)包
  3. 完成通信

注意 重點(diǎn)

到此,你以為結(jié)束了? 那就大錯(cuò)特錯(cuò)了。
到這里你會(huì)發(fā)現(xiàn),接收方(以下統(tǒng)稱A)可能拿不到數(shù)據(jù)包,這種情況出現(xiàn)在接收方在局域網(wǎng)內(nèi)(需要穿透NAT)。
前面講的,并不是僅僅獲取到設(shè)備外網(wǎng)地址就可以成功穿透,還要注意NAT會(huì)把不認(rèn)識(shí)的數(shù)據(jù)丟棄。
這是為什么?
NAT丟棄了你這個(gè)來源不明的包,根本沒有分發(fā)給接收設(shè)備A。
為什么叫來源不明呢,這是因?yàn)槭紫華的UDP端口給服務(wù)器發(fā)數(shù)據(jù)包,A的NAT創(chuàng)建了一個(gè)session,這樣A再接收到服務(wù)器的數(shù)據(jù)時(shí),會(huì)查找這個(gè)映射(A<--->服務(wù)器),這個(gè)映射就儲(chǔ)存在這個(gè)session里。但是發(fā)送方(B)向A的NAT發(fā)送數(shù)據(jù)(這是在B的NAT建立對(duì)A的映射),沒有指向B的映射,所以數(shù)據(jù)包被A的NAT丟棄。
那怎么解決呢,其實(shí)讓A也向B發(fā)一個(gè)數(shù)據(jù)包就好了,這樣A的NAT會(huì)建立一個(gè)對(duì)B的session,這樣再收到B的數(shù)據(jù)NAT就可以查找到對(duì)應(yīng)的映射了。

之前提到的NAPT對(duì)UDP的session映射,源地址相同,源端口相同,目標(biāo)地址不同,對(duì)于不同的NAPT,session可能不同。這條規(guī)則是依據(jù)不同的NAT的。Symmetric NAPT會(huì)導(dǎo)致session不同,Cone NAPT則是相同的。對(duì)于p2p只要一方使用的是Symmetric NAPT就會(huì)導(dǎo)致無法穿透。具體可自行百度。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容