NAT穿越-TCP打洞
TCP打洞
在處於NAT之後的兩臺主機之間建立p2p TCP連線比建立相應的UDP要稍微複雜,但在協議層次,TCP打洞非常類似與UDP打洞。然而TCP協議本身比較複雜,因此支援的NAT比較少。然而,在NAT支援TCP打洞的情況下,TCP打洞像UPD打洞那樣快並且可靠。穿透“行為良好”的NAT的TCP p2p連線事實上比UDP連線更健壯,因為,TCP協議的狀態機給路徑上的NAT提供了一種決定特定TCP連線確切生存週期的標準方式,而維持UDP連線的時間是不確定的。
套接字和TCP埠重用
對於想實現TCP打洞的應用程式來說,實際面臨主要的挑戰不是協議問題,而是API的問題。因為標準的Berkeley sockets API是圍繞C/S程式設計而設計的。這個API通過connect()允許一個TCP流套接字初始化一個向外的連線,通過listen()和 accept()監聽一個外入的連線,一個套接字不能既用來監聽又用來初始化向外的連線。更進一步講, TCP套接字通常與本地主機上的TCP埠一一對應:一個套接字繫結到本地主機機上的某個埠後,另一個套接字就不能再繫結到該埠。
然而TCP打洞要成功,需要一個本地的TCP埠既可以監聽外入的連線,同時又可以發起多個向外的連線。幸運的是,所有主流的作業系統都支援一個特殊的socket選項,通常叫做SO_REUSEADDR,它執行應用程式繫結多個設定了該選項的套接字到同一埠。BSD系統引入了SO_REUSEPORT選項來控制埠重用,從而把埠重用和地址重用相分離。在這樣的系統中,兩個選項都需要被設定。
開啟對等TCP流
假定Client A想要同Client B建立一個TCP連線。我們假設Client A和 Client B都與一個雙方都知道的集結伺服器S保持著一個活動的TCP連線。這個伺服器記錄了每一個註冊客戶端的公有和私有地址,這類似於UDP打洞的情況。在協議層,TCP打洞幾乎和UDP一樣:
- Client A利用與S的連線請求S幫助它連線到B
- S把B的公有和私有地址告訴A,同時把A的公有和私有地址告訴B。
- A和B都通過相同的本地TCP埠向S返回給它們的地址(公有和私有地址都發)發起一個向外的連線嘗試,同時在它們各自的本地埠上監聽外入的連線。
- A和B等待向外的連線嘗試成功,或者一個外入的連接出現。如果由於”connection reset”或”host unreachable”這樣的網路錯誤引起一個向外的連線嘗試失敗,主機就簡單的延遲一段時間(比如1秒)之後再嘗試連線,直到出現一個應用程式定義的最大超時。
- 當一個TCP連線建立之後,主機通過驗證彼此以確定它們連線到了目的主機。如果驗證失敗,客戶端就關閉連線等待另一個連線。一旦找到一個驗證成功的TCP流連線,這一過程就終止。
不像UDP,這裡每個客戶端只需要維持一個與S的連線,而不管同時有多少個對端。TCP方案中,每一個客戶端應用程式必須管理多個繫結到同一個本地埠的sockets。如下圖所示。
每個客戶端需要一個流套接字來與S連線,一個套接字來監聽來自對端的外入連線,至少兩個另外的流套接字用來發起到對端公有地址和私有地址的向外的TCP連線。如下圖所示,考慮到通常的情況都是,A和B位於不同的NAT之後,A和B發起的到對端私有地址的連線嘗
試可能失敗或連線到錯誤的主機。類似於UDP的情況,TCP應用程式驗證它們的端到端會話也是很重要的,因為可能發生這樣的情況:連線到一個本地網路中與想要連線的遠端主機具有同一個私有地址的主機上。
這些客戶端發起的到對端公網地址的連線嘗試,促使它們各自的NAT開啟一個新的“洞”,這個“洞”允許A和B可以直接進行TCP通訊。如果它們之間的NAT是“行為良好”,就會自動在它們直接形成一條p2p TCP流。如果A發到B的第一個SYN包在B發到A的第一個SYN包到底B的NAT之前到達該NAT,那麼B的NAT會把A的SYN包當做未授權的外入連線嘗試而把該SYN包丟棄。隨後B的第一個SYN包應該能順利通過,因為A的NAT把它當做A的第一個SYN包已經發起的向外連線的一部分。
應用程式觀察到的行為
客戶端應用程式在它們的sockets上觀察到的行為依賴於時機和TCP實現。假定A外發到B的公共端的第一個SYN包被B的NAT丟棄,但是隨後的B傳送到A的公共端的第一個SYN包在A重新發送SYN包之前穿過網路到達了A,依賴於涉及到的作業系統,將發生下述行為之一:
- A的TCP實現通知會話終端,這個外入的SYN匹配A起先發起的向外會話。因此A的協議棧就把這個新會話與該socket聯絡在一起,A的本地應用程式使用connect()連線B的公共端。應用程式的非同步呼叫connect()成功,監聽socket什麼也沒有發生。
然而收到的SYN包沒有包含先前A外發的SYN包的ACK,A的TCP迴應B的公共端一個SYN-ACK包,其中SYN部分只是初始外發SYN的重複,即使用同樣的SYN序列號。一旦B的TCP收到A的SYN-ACK,它用它自己的ACK迴應A的SYN,之後兩端之間的TCP會話就建立起來了。 - 作為另一種選擇,與上一種情況不同,A的TCP實現可能通知應用程式,在那個埠上有一個活動監聽套接字正在等待連線嘗試。因為B的SYN包看起來像一個外入的連線嘗試,所以A的TCP建立一個新的流套接字並把它和這個新的TCP會話結合在一起,並通過應用程式的在它的監聽埠的下一次accept呼叫返回給應用程式。A的TCP隨後迴應B一個上述的SYN-ACK,隨後的TCP連線建立處理就和通常的C/S一樣。
因為先前A到B的向外connect()嘗試所使用的源和目的地址結合正在被另一個socket使用,即剛剛通過accept()返回給應用程式的socket,所以A非同步呼叫的connect()在某個時間肯定會失敗,通常是返回一個“address in use”錯誤。然而已經有一個可以工作的p2p 流socket用於與B通訊,所以可以簡單的忽略該失敗。
上述的第一行為通常出現在BSD系統中,第二種行為通常出現在Linux和Windows系統中。
TCP同時開放
假定我們解決了打洞過程中的各種各樣連線嘗試的時機問題,以便來自兩個客戶端的外發SYN包穿過了它們各自的本地NAT,在到達遠端對端的NAT之前在每個NAT上打開了向外的TCP會話。在這種“幸運”的情況下,NAT沒有阻擋這兩個初始SYN包,這兩個SYN包在兩個客戶端各自的NAT之間的線路上交叉通過。在這種情況下,客戶端觀察到了被稱為同步TCP開放的事件:每一個對端在等待SYN-ACK的時候收到了一個“raw”SYN。每一個對端的TCP迴應對方一個SYN-ACK,其中的SYN部分是初始外發SYN的重複,ACK是對各自收到的SYN的確認。
在這種情況下,各自的應用程式觀察到的行為也依賴於TCP的實現,如上一部分所述。如果兩個客戶端都實現了上述的第二種行為,可能是這樣:所有由應用程式非同步呼叫的connect()最終都失敗了,但是執行在每個客戶端的應用程式通過accept()收到了一個新的、可以工作得p2p TCP 流套接字 – 好像TCP流魔術般的線上路上建立了它自身,而終端只是被動的接受這個流。應用程式不關心最終的流是通過connect()還是accept()收到的,這個過程在任何正確實現了標準TCP狀態機的TCP實現上產生了一個可以工作的流。
相關推薦
NAT穿越-TCP打洞
TCP打洞 在處於NAT之後的兩臺主機之間建立p2p TCP連線比建立相應的UDP要稍微複雜,但在協議層次,TCP打洞非常類似與UDP打洞。然而TCP協議本身比較複雜,因此支援的NAT比較少。然而,在NAT支援TCP打洞的情況下,TCP打洞像UPD打洞那樣快並且可靠。穿透
TCP實現P2P通訊、TCP穿越NAT的方法、TCP打洞
Internet的迅速發展以及IPv4 地址數量的限制使得網路地址翻譯(NAT,Network Address Trans2lation)裝置得到廣泛應用。NAT裝置允許處於同一NAT後的多臺主機共享一個公網(本文將處於同一NAT後的網路稱為私網,處於NAT
TCP 打洞原理
UDP打洞技術: 對於兩個peer,A和B。 1、若A和B位於同一個nat之後。如果nat支援迴環轉換,A和B之間打洞時使用彼此的外網地址是可以連通的。但是最好是優先嚐試內網連線。 2、若A和B位於不同的nat之後。若兩個nat都是公網地址,則屬於“典型”連線過程,連線相對簡單可靠。 3、若A和
關於TCP打洞技術(P2P)
建立穿越NAT裝置的p2p的TCP連線只比UDP複雜一點點,TCP協議的"打洞"從協議層來看是與UDP的"打洞"過程非常相似的。儘管如此,基於TCP協議的打洞至今為止還沒有被很好的理解,這也造成了對其提供支援的NAT裝置不是很多。在NAT裝置支援的前提下,基於TCP的"打洞
P2P技術 TCP打洞 內網穿透
程式語言:C/C++ 主要使用:SOCKET套接字 程式設計軟體:VS2015 技術實現:P2P TCP打洞 內網穿透實驗 原始碼:http://download.csdn.net/download/a
TCP打洞和UDP打洞的區別
為什麼網上講到的P2P打洞基本上都是基於UDP協議的打洞?難道TCP不可能打洞?還是TCP打洞難於實現? 假設現在有內網客戶端A和內網客戶端B,有公網服務端S。 如果A和B想要進行UDP通訊,則必須穿透雙方的NAT路由。假設為NAT-A和NAT-B。 A傳送資料包到公
TCP打洞與UDP打洞的區別
為什麼網上講到的P2P打洞基本上都是基於UDP協議的打洞?難道TCP不可能打洞?還是TCP打洞難於實現? 假設現在有內網客戶端A和內網客戶端B,有公網服務端S。 如果A和B想要進行UDP通訊,則必須穿透雙方的NAT路由。假設為NAT-A和NAT-B。
NAT穿透(UDP打洞)
會有 work true icmp sea 類型判斷 無法 部分 什麽 1、NAT(Network Address Translator)介紹 NAT有兩大類,基本NAT和NAPT。 1.1、基本NAT 靜態NAT:一個公網IP對應一個內部IP,一對一轉換 動態NAT:N
【原創】IP攝像頭技術縱覽(七)---P2P技術—UDP打洞實現內網NAT穿透
【原創】IP攝像頭技術縱覽(七)—P2P技術—UDP打洞實現內網NAT穿透 本文屬於《IP攝像頭技術縱覽》系列文章之一: Author: chad Mail: [email protected] 本文可以自由轉載,但轉載請務必註明
試驗UDP打洞穿透NAT
目標 路由穿透,實現廣域網P2P通訊。 4種典型NAT型別 按照NAT裝置在進行地址對映時行為的不同,NAT可以分為以下四種: Full Cone Restricted Cone Port Restricted Con
UDP打洞NAT大致分為下面四類 P2P
NAT大致分為下面四類 1) Full Cone 這種NAT內部的機器A連線過外網機器C後,NAT會開啟一個埠.然後外網的任何發到這個開啟的埠的UDP資料報都可以到達A.不管是不是C發過來的. 例如 A:192.168.8.100 NAT:202.100.100.100
NAT穿透技術詳解(udp打洞精髓附程式碼)
以前自己寫的程式碼都只是在本地進行c/s通訊,今天想寫一個可以跨越外網的c/s通訊,這裡我就用udp實現一個點對點的不同外網的通訊。用到的技術就是nat穿透技術,這裡最直接使用的就是udp打洞技術。文中如有表述不清楚,歡迎提問。如果你需要nat穿透技術的詳解點這裡:nat穿透
UDP用打洞技術穿透NAT的原理與實現
首先先介紹一些基本概念: NAT(Network Address Translators),網路地址轉換:網路地址轉換是在IP地址日益缺乏的情況下產生的,它的主要目的就是為了能夠地址重用。NAT分為兩大類,
NAT路由器“打洞”技術,即P2P通訊實現原理(非常詳細)
什麼是打洞,為什麼要打洞 由於Internet的快速發展 IPV4地址不夠用,不能每個主機分到一個公網IP 所以使用NAT地址轉換。 下面是我在網上找到的一副圖 一般來說都是由私網內主機(例如上圖中“電腦A-01”)主動發起連線,資料包經過NAT地址轉換後送給公網上的伺服器(例如上圖中的“Server”)
NAT穿透,UDP打洞程式
在看NAT穿透和UDP打洞原理,網上都是講原理,沒有程式,我把程式寫出來。 server.py,輔助打洞的伺服器。 peer.server.py,被打洞的節點。 peer.client.py,主動打洞的節點。 基本原理是: 1. peer.client向peer.serve
C# UDP NAT 打洞 程式碼示例
打洞原理: 名稱 IP Port PC-A 192.168.1.217 8000 NAT-A 61.188.71.155 50020 PC-B 192.168.1.117 8000 NAT-B 61.
Autossh打洞
ssh authossh 打洞 autossh介紹:autossh 是一個用來啟動 ssh 並進行監控的程序,可在需要時重啟 ssh,如果程序問題或者是網絡問題。其靈感和機制來自於 rstunnel (Reliable SSH Tunnel). autossh 1.2 的方法已經改變:autoss
C++從零開始區塊鏈:P2P模組之打洞伺服器
原則上說,打洞伺服器應該是可以返回多個節點的,這裡為了簡化,只返回一個節點。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #i
Darwin Streaming Server 支援UDP打洞
RTSP客戶端點播Darwin 視訊時,SDP協商後的客戶端埠可能是在NAT後面,所以需要Darwin支援NAT打洞的功能,從Darwin的原始碼看,官方的原始碼是不支援這個能力的。 通過抓取VLC客戶端的包發現,VLC在播放RTSP流時,兩次SETUP(音訊流和視訊分別協商埠)之後,
P2P打洞原理
一、P2P打洞原理 1、打洞解決了什麼問題? 我們平常使用的一般都為私有ip,但是私有ip之間是不能直接通訊的,如果要進行通訊只能通過公網上的伺服器進行資料的轉發,難道我們每次傳送資料都要經過公網上的伺服器轉發嗎?也不是不可以,但是伺服器的承受能力就會大大增加。此時就需要我們的打洞技