網路上大多數的服務都是主從式架構
顧名思義就是會有台server一直listen著某個port
隨時準備好有client連進該ip該port來request他所要資源
可是萬一我今天想要的資源(e.g. 今天的課堂筆記)並不是在一台隨時待命的server上
而是我朋友的電腦裡,我想要與他通訊交換檔案呢(醒醒吧,我沒有朋友)
於是最簡單的peer-to-peer模型出現了
兩端直接在Public Network中
朋友跟我說他的ip以及socket監聽的port,等待我與他建立了一條socket連線
接著就可以把今天的課堂筆記拷貝回家了
+------>>------------------------+ | | | | 我的電腦 朋友的電腦 75.129.48.33:50001 75.129.48.50:50001
於是本文寫到這邊就可以結束了XDD
其中一端在NAT後面
當然現實總是沒有那麼美好
在日常的網路當中,網路設備通常是在防火牆或NAT後面
例如我的幻想朋友家族成員眾多
所以他在家裝分享器好讓爺爺奶奶外公外婆舅舅舅媽阿姨叔公伯伯...族繁不及備載,能同時間連上網
+------>>------------------------+ | | | NAT B | 75.129.48.50 | | | | 我的電腦 朋友的電腦 75.129.48.33:50001 192.168.1.3:50001
如果此時我一樣發送了建立socket連線請求的封包到朋友的外網ip(75.129.48.50:50001)
他家的分享器(NAT B)會很困惑這個封包應該轉發給內網的哪個設備
即便朋友的電腦正在監聽port 50001
接著就直接把封包給丟棄了(幫QQ)
如果送到192.168.1.3:50001更不可能會到,因為192.168.X.X是Class C網段的內網ip位址
為了能夠成功連線,我們把連線方式反過來
換我跟朋友說ip以及socket監聽的port,請朋友連過來
朋友的socket連線請求封包先經過了NAT B(分享器),NAT B再以自己的名義(75.129.48.50:33941)轉發到我的電腦(75.129.48.33)
+------------------------<<------+ | | | NAT B | 75.129.48.50:33941 | | | | 我的電腦 朋友的電腦 75.129.48.33:50001 192.168.1.3:50001
在這個轉發的過程中,NAT B不一定會使用與前一段相同的port
有可能這個port已經被其他應用程式佔用走了,像上圖一樣
封包從朋友的電腦port 50001發出,但在NAT B是以port 33941轉發給我的電腦
我的電腦因為是直接接到public network,所以封包可以順利的接收
站在我的電腦的觀點來看,封包是來自75.129.48.50:33941
因此,我的電腦會以為朋友的socket連線是在75.129.48.50:33941,而往後所有回覆的封包都會往75.129.48.50:33941送,實際上這是NAT B位址
+------>>------------------------+ | | | NAT B | 75.129.48.50:33941 | | | | 我的電腦 朋友的電腦 75.129.48.33:50001 192.168.1.3:50001
NAT B在收到封包後,因為曾經將來自內網192.168.1.3:50001的封包從75.129.48.50:33941轉發出去
所以在它的NAPT表(Network Address Port Translation Table)中會有一條這樣的forwarding rule
75.129.48.50:33941<-->192.168.1.3:50001
NAT B根據這個forwarding rule,知道送到75.129.48.50:33941的封包是屬於192.168.1.3的
最後將這個封包往內網的192.168.1.3:50001送
這樣就完成了一次封包來往的cycle
往後的封包也是這樣的原理在NAT之間穿越
我也就可以把今天的課堂筆記順利拷貝回家了,YA!!
兩端都在NAT後面
上述的情況還是太理想了,現實應該要更殘酷
如果今天我家跟我朋友家雙邊都有了NAT(分享器),難道就無解不能P2P通訊了嗎
+--------------------------------+ | | NAT A NAT B 75.129.48.33 75.129.48.50 | | | | 我的電腦 朋友的電腦 192.168.1.3:50001 192.168.1.3:50001
這個例子應該是最接近現實狀況的,甚至現實中的NAT還不只一層
所以接下來要介紹現實中常用將雙方在NAT後的設備建立P2P連線的方式(好長的鋪陳)
UDP打洞 (UDP hole punching)
還記得在其中一端在NAT後面這段時有提到,NAT轉發時不一定會使用與前一段相同的port
為了解決雙方都使用NAT隨機分派的port去訪問對方而port對不上的問題
我們需要再引進第三方(暫名Server)協助記錄雙方對外的ip以及p2p連線用的port
然後使用UDP打洞的技術來協助在NAT後面的雙方建立起連線
Server 122.116.185.28:50001 | | +---------------+---------------+ | | NAT A NAT B 75.129.48.33:63029 75.129.48.50:33941 | | | | 我的電腦 朋友的電腦 192.168.1.3:50001 192.168.1.3:50001
UDP打洞的步驟是這樣的:
- 我的電腦以及朋友的電腦都先跟Server以UDP的方式回報自己的ip以及使用的port
(由於雙方都在內網,所以雙方回傳的會是內網的ip以及port)
- 上面提到過其中一端在NAT後面是可以通訊的(Server在public network中)
-
Server記錄下「觀察到的」封包來源ip及port(所以會是雙方NAT對外的ip及port)
-
Server告訴雙方 對方的ip及port
- 由於雙方都已經跟Server用這個port通訊過,所以雙方NAT的NAPT表中已經有了forwarding rule
- 現在雙方就可以開始跟對方以UDP的方式通訊了,YA!!
表示只要雙方NAT的ip與port是雙方互相都知道的就可以實現p2p嗎?
那如果是這樣的話我直接透過通訊軟體轉達我和朋友雙方的ip與port,之後雙方都向對方NAT的ip與port傳送封包,也能達到一樣的效果嗎,這樣是不是就不一定要裝特定的程式(像是zerotier之類的)就能自己DIY P2P嗎?
(雖然實際執行起來說不定比安裝zerotier更加複雜.. 哈哈)