为什么网上讲到的P2P打洞基本上都是基于UDP协议的打洞?难道TCP不可能打洞?还是TCP打洞难于实现?
如果如今有内网clientA和内网clientB。有公网服务端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绑定到同一个本地port,而TCP的socket则不同意。
这是这样一个意思:A B要连接到S,肯定首先A B两方都会在本地创建一个socket。
去连接S上的socket。创建一个socket必定会绑定一个本地port(就算应用程序里面没写
port,实际上也是绑定了的,至少java确实如此),如果为8888,这样A和B才分别建立了到
S的通信信道。
接下来就须要打洞了,打洞则须要A和B分别发送数据包到对方的公网IP。
可是
问题就在这里:由于NAT设备是依据port号来确定session。假设是UDP的socket,A B能够
分别再创建socket,然后将socket绑定到8888。这样打洞就成功了。可是假设是TCP的
socket,则不能再创建socket并绑定到8888了。这样打洞就无法成功。
转自:http://f543711700.iteye.com/blog/978887