最近一陣子在研究內網穿透,查了很多資料,因此今天就聊聊兩種不一樣的穿透方式的原理,以及基於java的netty框架的實現,代碼也已在個人github。html
原由:忽然花這麼大力氣研究這個雖然是頭腦發熱所爲,但動機源於跟小夥伴聯機打遊戲,原來用nat123之類的作遠程端口轉發在最近一陣子巨慢無比,又沒找好的替代方案,前一陣子公司同事又分享過nio,網絡編程的知識又被過了遍,一拍腦子本身造輪子得了,正好本身又有個阿里雲能夠當中間節點,找了些參考文章就開搞了,陸陸續續摸索了三個週末,基本能夠用了,這兩篇文章就當總結了。java
在通常的網絡應用中,簡單拓撲模型以下
git
server有公網ip,server應用直接監聽公網ip及端口,client訪問可直接經過ip:port 直接創建連接,進行請求響應。github
但若是服務端經過路由連接Internet,沒有直接暴露公網ip就不一樣了,如如下拓撲算法
server在內網,沒有公網ip,路由有公網ip,經過路由連接Internet,client請求抵達server路由後,除非在路由定義端口轉發規則,不然數據將被拋棄,但不少時候路由的轉發規則是沒法被改的。編程
這樣的模型能夠細分爲四種狀況安全
對於server在公網的狀況,client能夠主動連接;但server在內網時,咱們便須要內網穿透了。接下文章將以最複雜的第4種狀況進行分析。服務器
對於client和server均在內網的狀況,直連是不行的,但若是咱們有另一臺具備公網ip的服務器充當中間節點,即可以進行間接訪問了,拓撲以下網絡
中間服務器咱們暫稱爲forwarder
咱們詳細描述下請求響應過程 框架
咱們能夠看到內網機器能訪問Internet的緣由在於它的路由爲其分配了一個隨機的公網端口。這裏順帶解釋概念 端口映射,此時的公網端口12.12.12.12:45464邏輯上能夠認爲就是內網機器777端口的映射。再抽象一點,對於client來講,forwarder的666端口其實也能夠認爲是server 80端口的映射,這個即是遠程端口映射,所以,遠程端口映射跟內網穿透,描述雖不一樣本質上是一致的。
這種模式很是簡單直接,只要client和server能連上Internet,就能穿透彼此的內網相互訪問。
諸如nat123的端口轉發機制,穿透內網的遠控軟件TeamViewer,咱們玩一些對戰遊戲的平臺,甚至各類網絡遊戲均可以當作這種模型的實現。
它的優勢在於forwarder服務器存在,能夠協助穿透任何形式的內網,簡單穩定,但一樣因爲存在中間服務器,網絡上不只受客戶端網絡限制,一樣也受forwarder的網絡限制,若是forwarder帶寬不行,或者傳輸幾g的大文件,效率就慢了。爲了解決這個問題,基於P2P的機制也就提出來了。
先回頭看下C/S模式的網絡拓撲
C跟S最終仍是由各自路由隨機分配的公網端口進行Internet訪問,這樣的話,若是它們能彼此知道對方的公網ip和端口,好比經forwarder將ip端口發給對方,是否是就能夠直接TCP實現P2P訪問呢,答案是比較困難的。
緣由在於TCP是一種先鏈接後傳輸的通訊協議,分配給client的45464只能與forwarder的666端口傳輸數據,這是在鏈接創建時肯定的,若是client再想連接server的路由,此時的端口將是從新分配的。而且由於安全等問題考慮,端口是隨機分配,沒法固定。也有一些資料說能夠經過某些算法猜想到公網端口從而實現基於TCP的P2P傳輸,但實現起來比較困難。咱們這裏就經過UDP來實現,由於它跟TCP不一樣,是在發送數據時指定目標ip端口。
下面來看看基於UDP的P2P模式的網絡拓撲
如下是請求響應過程
P2P方案優勢也就明顯的,數據傳輸不依賴於中間服務器,在鏈接創建後就再也不受其限制,但一樣因爲UDP的特性,數據可靠性難以保證,因此得容忍偏差,或者實現一些校驗機制,並且對於Symmetric NAT,P2P是沒法創建的,仍是隻能走C/S模式的穿透。
它的應用最普遍的就是各類BT客戶端了,畢竟大數據的傳輸不須要通過中間服務器,效率會高不少,而後一些P2P的聊天,視頻,遊戲對戰軟件也能夠用到。
至此,兩種實現模式的原理已經說明了,下一篇將講講基於java netty框架造的兩個輪子。
內網穿透並非一個新話題,已經有不少成熟的協議和框架實現了,好比這個,但學習,仍是本身造輪子得好。
做者:chulung
原文連接:https://chulung.com/article/36
本文由MetaCLBlog於2017-02-25 17:39:27自動同步至cnblogs
本文基於 知識共享-署名-非商業性使用-禁止演繹 4.0 國際許可協議發佈,轉載必須保留署名及連接。
出處:http://www.cnblogs.com/chulung/p/5657073.html