其实这个原理至为简单,因为NAT的作用就是转换数据包的IP和PORT(端口号),局域网内所有的数据包都会把IP改变为公网的IP,而端口号是随机产生的,但是路由器会记住每个连接的端口和IP的对应关系,这样外网来的数据,会按照这个对应分发。这个术语好像叫NATP,就是转换的意思吧。从原理上来说,外网完全不用理睬内网的IP和端口号(事实上一般方法也无法知道),它只要把数据包发送给转换后的端口和IP就可以了。现在问题是怎么知道这个转换后的端口和IP,IP当然很容易知道,因为他基本是不变的。而端口号对于不同的通讯方式,分不同的情况。对于UDP而言,因为不用连接,只要Send数据就可以了,你向服务器Send一个数据,服务器就知道你这个socket的外网端口了,你向其它IP和端口Send数据,这个外网端口是不变的,这就是关键,除非你Close了这个socket,或者长时间不Send数据,NAT才会改变这个端口号。当你使用UDP 对一个特定的IP和端口Send数据,实际上就打开了一个通道(所谓的Hol),对应IP(你Send数据的IP)的主机只要对这个端口Send数据,数据包就会被接受,并且转换为逆向的数据包。对于TCP而言,可以采用一样的思路,只不过Send变成了Connect,现在问题来了,一个Socket Connect后,它的使命就完成了,你再也不能用它连接其他的节点,这个UDP的情况是不同的。如果你又Create了一个socket,你又无法保证它的外网端口是不变的。我测试的结果,每个socket都会有自己的外网端口,即使你把本地端口设置的一样,每次连接这个外网的端口都是不一样的。

解决方案 »

  1.   

    我现在唯一想到的可行的方法就是猜,双方同时发起连接,如果猜对了这个端口,连接就会成功,而连接成功之前,没人知道这个孔的外网端口。另一种方法是UDP打开的孔,TCP能不能连进来?
      

  2.   

    怎么会是猜呢“它的使命就完成了,你再也不能用它连接其他的节点”重用端口~setsockopt
      

  3.   

    楼上重用端口是什么意思?SOCKET s = socket(...);
    connect(s,addr,....);
    连接成功
    你能用setsockeopt让他连上另一个服务器?
      

  4.   

    网上有很多代码,但是主要受NAT不同的限制.
    还不如直接UPNP呢,至少多数路由都支持,限制没有TCP打洞这么大
      

  5.   

    实际上就打开了一个通道(所谓的Hole