其實很早我就已經實現了使用tcp協議穿透nat了,但是苦於一直沒有時間,所以沒有寫出來,現在終於放假有一點空閒,於是寫出來共享之。
一直以來,說起nat穿透,很多人都會被告知使用udp打孔這個技術,基本上沒有人會告訴你如何使用tcp協議去穿透(甚至有的人會直接告訴你tcp協議是無法實現穿透的)。但是,眾所周知的是,udp是乙個無連線的資料報協議,使用它就必須自己維護收發資料報的完整性,這常常會大大增加程式的複雜度,而且一些程式由於某些原因,必須使用tcp協議,這樣就常常令一些開發tcp網路程式的人員「談穿透色變」。那麼,使用tcp協議是不是就不能實現穿透呢?答案當然是否定的:tcp協議不僅能實現nat穿透,而且實現起來比udp穿透甚至還簡單一些。
用udp來實現以上3步不存在什麼理論上的問題,因為udp是無連線的協議,它允許socket進行「多對一」的通訊(即幾個具有不同ip和埠號的socket向乙個接收socket傳送訊息)。但是使用tcp就出現了問題:在一般情況下,tcp socket不允許在已經建立連線的埠上再進行監聽和使用該本地埠。換句話說,當ab連線上伺服器s後,s將ab的實際終端告訴對方,下一步本該是ab利用對方的實際終端進行直連,但這時你會發現對方的實際終端已經被占用了(就是各自連線到伺服器s的會話占用了終端),無法同時listen和 connect。於是很多人得出結論:tcp無法實現nat穿透。
於是問題的關鍵變成了如何復用乙個tcp連線的本地終端,這其實不是協議的問題,而是乙個api的問題。幸運的是,所有主流作業系統都支援乙個特定的tcp套接字選項——so_reuseaddr。這個選項允許將多個socket繫結到同乙個本地終端。我們建立socket的時候只要加上這麼一行:
&flag, len) ;
//c++就這麼做
true
) '
這是vb.net 更加簡單
知道上面的知識就很好辦了,下面我來說說tcp協議的穿透流程:
機器布局還是和上面使用udp的一樣。現在假設客戶a想和客戶b建立tcp連線。
首先還是 ab分別和伺服器s分別建立連線,s記錄ab的網際網路實際終端。然後s分別向ab傳送對方的實際終端。接著,從a和b向s連線時使用的埠,ab都非同步呼叫connect函式連線對方的實際終端(就是s告訴的終端),同時,ab雙方都在同乙個本地埠監聽到來的連線(也可以先監聽,再connect更好)。由於雙方都向對方傳送了connect請求(假設各自的syn封包已經穿過了自己的nat),因此在對方connect請求到達本地的監聽埠時,路由器會認為這個請求是剛剛那個connect會話的一部分,是已經被許可的,本地監聽埠就會用syn-ack響應,同意連線。這樣,tcp穿透nat的點對點連線就成功了。
**中有乙個我自己封裝的模仿vb6 winsock的控制項zxmsocket,這個socket可以讓你設定是否使用so_reuseaddr引數,socket是事件驅動的。
如果你要測試**,需要使用乙個bat來啟動傳送和接收程式(檔案格式請參照bin/debug資料夾下的run.bat檔案),這個bat的功能是以命令列的方式告訴程式登入伺服器縮使用的使用者名稱,對於伺服器來說,這個使用者名稱必須是唯一的,當然,這可能有點不科學,但是這畢竟只是乙個demo。
使用TCP協議的NAT穿透技術
要了解如何使用tcp穿透nat,就要首先看看如何使用udp穿透nat。假設,我們在兩個不同的區域網後面分別有2臺客戶機a和 b,ab所在的區域網都分別通過乙個路由器接入網際網路。網際網路上有一台伺服器s。現在a b是無法直接和對方傳送資訊的,a b都不知道對方在網際網路上真正的ip和埠,ab所在的區...
使用TCP協議的NAT穿透技術
實很早我就已經實現了使用tcp協議穿透nat了,但是苦於一直沒有時間,所以沒有寫出來,現在終於放假有一點空閒,於是寫出來共享之。一直以來,說起nat穿透,很多人都會被告知使用udp打孔這個技術,基本上沒有人會告訴你如何使用tcp協議去穿透 甚至有的人會直接告訴你tcp協議是無法實現穿透的 但是,眾所...
使用TCP協議的NAT穿透技術
一直以來,說起nat穿透,很多人都會被告知使用udp打孔這個技術,基本上沒有人會告訴你如何使用tcp協議去穿透 甚至有的人會直接告訴你tcp協議是無法實現穿透的 但是,眾所周知的是,udp是乙個無連線的資料報協議,使用它就必須自己維護收發資料報的完整性,這常常會大大增加程式的複雜度,而且一些程式由於...