再谈UDP穿透NAT的实现(200分)

  • 主题发起人 主题发起人 yqlqq
  • 开始时间 开始时间
Y

yqlqq

Unregistered / Unconfirmed
GUEST, unregistred user!
最近尝试做一个P2P的通信项目,无可避免要碰到两个客户端处于不同的局域网里面的问题,于是查阅了大量的相关资料,其实关于UDP穿透NAT的原理我想应该大家都了解,我就简单的说说吧!

            Server
     ┌─────────┴─────────┐
     NAT1                  NAT2
     │                   │
    Client1                 Client2

说明:
 Server 是服务端,放在有公网IP的机器上
 Client1 是客户端1,在局域网NAT1里
 Client2 是客户端2,在局域网NAT2里

那么,Client1 如何与 Client2 进行P2P的通信呢,根据我的理解,我想原理应该是以下这几个步骤:

1、Client1 登录 Server, Server 记录 Client1 的IP及PORT(IP1:Port1)
2、Client2 登录 Server, Server 记录 Client2 的IP及PORT(IP2:Port2)

3、Client1 发命令到 Server 取得 Client2 的IP及PORT
4、Client1 发包给(IP2:Port2) 即 Client2,打开一个洞用于接受 Client2 发来的包
5、Client1 发命令到 Server 让 Server 发包到 Client2 告知 Client2,Client1 的IP及PORT,并命令 Client2 发包到 Client1

6、Client2 收到 Server 发的来包后,发包到 Client1, 同时打开一个泂接受 Client1 发来的包

通过以上的六个步骤,Client1 与 Client2 已经实现了 P2P 的连接了,这是我理解的实现原理,本人接触网络编程才不久,如果理解有误,恳请指正。

原理弄清楚了以后,我马上就用Indy9里的IdUDPServer控件做了个测试,结果到最后一步,也就是 Client2 向 Client1 发包的时候,Client1 马上出现 Socket Error # 10054 错误,无法实现 P2P 连接,我再仔细的检查了代码,完全符合以上原理,但经过多次的测试,还是一样出现错误,郁闷啊!

不知大富翁里有没有那位高手有实现过相关功能的项目呢,希望能指点一下,无限感谢!
 
不好意思没做过,帮忙顶一下
 
4、Client1 发包给(IP2:Port2) 即 Client2,打开一个洞用于接受 Client2 发来的包
这步不对.应该不是IP2:Port2,这样肯定会被Client2的NAT丢弃的.

你的理解我觉得有不正确的地方,A,B两个不同NAT后面的无法直接连接主要的问题就是两端之间没有一条维护双方通信的Session.
比如A出了NAT后地址及IP会被转换,这个转换后的地址只有NAT知道,假如A出去后连接了C(另一个独立IP),这时候如果C连接A,A的NAT会知道这是A主动连接的地址,他就会将C的数据转发到A上,这样C发送到A的数据A就可以收到.(这是一个NAT后面的IP和一个独立IP的情况)
但是如果A,B都处于两个NAT的后面就需要由第三方来帮助建立两端之间的连接,由第三方模拟其中任何一方连接对方.使NAT相信这是我所管辖的内部地址主动发出的连接,NAT就会把数据转发到内部IP上.
 
注意你的步骤:4和6,两次打的洞并非同一根管道,
你在各自工程里面同时放入IdUDPServer和idUDPClient,实现对连
欢迎共同探讨
 
我的建议:
1,出现Socket Error # 10054 异常,就让它异常好了.你的程序继续运行.
2,Client1,Client2互相向对方发包的过程,决不是一问一答就可以了(一问一答就打通是理想的情况).你让它们互相同时对发.反正是它们的事,你不会感觉累.
3,有的网关.如端口受限型圆锥型网关,在用同一端口向不同地址发包时,会话端口会改变.所以,你的打洞包要利用这一点,及时更新对方的Port值.
 
To:总有爱
 Client1 首次发包给 Client2 时,NAT2当然会丢掉这个包,但NAT1以经向(IP2/Port2)发过包了,当然它收到(IP2/Port2)发来的包时,NAT1会认为这是主动连接的地址,而不会丢掉包,这理解不对吗?

To:超级牛X
两次打的洞并非同一根管道,这如何理解呢,怎么样才能做到同一管道呢?

To:夜
  我在两个Client中都用了定时器不断的发包,结果还是不断的出现错误,无法打洞成功

问题没还解决,请大家继续讨论,谢谢!
 
再谈,我来听听。
 
to yqlqq
问题不是要实现同一根管道
用上行下行两根管道做吧,同时放入IdUDPServer和idUDPClient
 
IdUDPServer
就足够了
 
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2391151
 
正在研究这个问题,参加.
 
要维持打洞必须不时的发送心跳。
 
不太了解,但还是感谢分享,关注中。。。
 
其实有Server的话就好办了,可以采取Client主动式通信,Client1发送命令到Server上,Client2读取命令,然后发送需要的数据到Server上,Client1再由Server读取数据,这样Servr作为一个中转,不知可行否?
 
to raylo
P2P的作用是减轻Server的压力,握手、心跳等简短指令当然可以通过Server中转,但是大数据量传输就必须避开Server了
 
我还是不太了解[:(]
 
TO:超级牛X
 能不能详细点呢,可以发个Demo给我吗(qylin2@163.com)
QQ:523241035
 
根据我对《UDP穿透NAT的原理》的理解觉得步骤应该是这样的,也不知道对不对。
1、Client1 登录 Server, Server 记录 Client1 的IP及PORT(IP1:Port1)
2、Client2 登录 Server, Server 记录 Client2 的IP及PORT(IP2:Port2)
3、Client1 发命令到 Server 取得 Client2 的IP及PORT,并要求Server发包到Client2,让Client2 向Client1 发包。
4、Client2 收到 Server 发的来包后,发包到 Client1, 同时打开一个泂接受 Client1 发来的包
5、Client1 发包给(IP2:Port2) 即 Client2,这时Client2就能收到Client1 的包了。
 
>>由第三方模拟其中任何一方连接对方.使NAT相信这是我所管辖的内部地址主动发出的连接,NAT就会把数据转发到内部IP上.

这种模拟是不是要修改IP包的源地址和port为另一client的IP和port?
 
按照我的经验,绝大部分的不同NAT,理论上是很难实现直接通讯的,为何说很难了,而不是绝对呢,这里还存在一个几率的问题,看运气了。
我只说一句:发给谁,就只能接受谁的,这个端口就只对谁有效,其他人得到这个端口,毫无意义。(这是大部分NAT的类型,80%左右)
我希望大家不要做无谓的浪费。我实在看不下去了,才出来说上两句。大家如果不信,就慢慢试,等试过了,用事实说话!
 
后退
顶部