為什么網上講到的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了,這樣打洞就無法成功。
http://www.cnblogs.com/key-ok/p/4367386.html