爲何網上講到的P2P打洞基本上都是基於UDP協議的打洞?難道TCP不可能打洞?仍是TCP打洞難於實現?
假設如今有內網客戶端A和內網客戶端B,有公網服務端S。
若是A和B想要進行UDP通訊,則必須穿透雙方的NAT路由。假設爲NAT-A和NAT-B。
A發送數據包到公網S,B發送數據包到公網S,則S分別獲得了A和B的公網IP,
S也和A B 分別創建了會話,由S發到NAT-A的數據包會被NAT-A直接轉發給A,
由S發到NAT-B的數據包會被NAT-B直接轉發給B,除了S發出的數據包以外的則會被丟棄。
因此:如今A B 都能分別和S進行全雙工通信了,可是A B之間還不能直接通信。
解決辦法是:A向B的公網IP發送一個數據包,則NAT-A能接收來自NAT-B的數據包
並轉發給A了(即B如今能訪問A了);再由S命令B向A的公網IP發送一個數據包,則
NAT-B能接收來自NAT-A的數據包並轉發給B了(即A如今能訪問B了)。
以上就是「打洞」的原理。
可是TCP和UDP在打洞上卻有點不一樣。這是由於伯克利socket(標準socket規範)的
API形成的。
UDP的socket容許多個socket綁定到同一個本地端口,而TCP的socket則不容許。
這是這樣一個意思:A B要鏈接到S,確定首先A B雙方都會在本地建立一個socket,
去鏈接S上的socket。建立一個socket必然會綁定一個本地端口(就算應用程序裏面沒寫
端口,實際上也是綁定了的,至少java確實如此),假設爲8888,這樣A和B才分別創建了到
S的通訊信道。接下來就須要打洞了,打洞則須要A和B分別發送數據包到對方的公網IP。可是
問題就在這裏:由於NAT設備是根據端口號來肯定session,若是是UDP的socket,A B能夠
分別再建立socket,而後將socket綁定到8888,這樣打洞就成功了。可是若是是TCP的
socket,則不能再建立socket並綁定到8888了,這樣打洞就沒法成功。 java