1. 程式人生 > >TCP打洞與UDP打洞的區別

TCP打洞與UDP打洞的區別

為什麼網上講到的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://f543711700.iteye.com/blog/978887