我对P2P通俗易懂的理解

Tomb Raider游戏出了局域网版本之后我就开始研发互联网版本的联机游戏。之所以局域网版本的不能直接用在互联网上是因为未有解决局域网内主机与外部网络或者与其他局域网的内部主机之间的通信问题。按照一般的P2P程序开发流程,需要一个拥有公网IP的服务器使用UDP Hole Punching技术可以达到把两个不同局域网的主机连接起来的目的,前提是局域网必须是属于圆锥型网络(Cone)而不是对称型的(Symmatric)。

圆锥和对称有何差别呢?

这里举个简单的例子。当你在局域网内向一台服务器A发送一个数据包时,网络地址转换器(NAT)会产生一个会话,并使用一个公网IP的端口与那台服务器通信,当那台服务器返回数据的时候,NAT会根据会话里的对应关系,把数据投递到局域网内你那台主机上。如果找不到对应关系,NAT是会把数据包丢弃的!通常还可能会收到10052的错误消息(Network dropped connection on reset.)这时候有一个这样的问题,当你的在局域网的那台主机使用同一个端口向另外一台服务器B(IP或端口不同)发送数据的时候,NAT创建一个新的对应关系时是否仍然会使用上次你跟服务器A通信时用的端口?如果会,那么它是圆锥型的,不会就是对称型的。

就像下图一样,



怎么样?画的还可以……还能想象出是圆锥和对称图形吧……

我也上网查过一些资料,包括国外的,比较详细,这里推荐一下:

http://midcom-p2p.sourceforge.net/draft-ford-midcom-p2p-01.txt

接着说,要使不同局域网内的两台主机进行通信,需要借助一台拥有公网IP的服务器来进行,看了步骤你就大概明白为什么要这样做啦!
假设ClientA(192.168.0.2:62001)和ClientB(10.0.0.2:30001)是两个不同的局域网里的主机,他们的公网地址分别是NAT_A 222.200.0.1:2222和 NAT_B 111.100.0.1:1111有一台拥有公网IP的Server 8.8.8.8:8888,具体的操作步骤是:

1、ClientA与Server通信,Server记录A的地址。

数据包路径 ClientA 192.168.0.2:62001 -> NAT_A 222.200.0.1:2222 -> Server 8.8.8.8:8888

2、ClientB与Server通信,请求Server建立A和B的通信连接。

数据包路径 ClientB 10.0.0.2:30001 -> NAT_B 111.100.0.1:1111 -> Server 8.8.8.8:8888

3、Server向ClientA转达ClientB的消息,并把B的公网地址111.100.0.1:1111告诉ClientA,同时返回消息给ClientB,告诉它ClientA的公网地址是222.200.0.1:2222。

数据包路径 Server 8.8.8.8:8888 -> NAT_A 222.200.0.1:2222 -> ClientA 192.168.0.2:62001
数据包路径 Server 8.8.8.8:8888 -> NAT_B 111.100.0.1:1111 -> ClientB 10.0.0.2:30001

4、ClientA收到Server转达的请求,向NAT_B发送一个空包,什么内容都可以,这样可以引起NAT_A创建一个从ClientA到NAT_B的对应关系。但是可以肯定,ClientB绝大部分是收不到这个数据包的。

数据包路径 ClientA 192.168.0.2:62001 -> NAT_A 222.200.0.1:2222 -> NAT_B 111.100.0.1:1111

5、同理,ClientB收到Server的回复,有了ClientA的公网IP,就向NAT_A发送一个空包,建立对应关系。如果NAT_A已经建立了对应关系,那么通常这个数据包ClientA是可以收到的。同样反过来也行,ClientB收到空包,ClientA收不到,这处决于哪一方先建立对应关系,但这不重要。

数据包路径 ClientB 10.0.0.2:30001 -> NAT_B 111.100.0.1:1111 -> NAT_A 222.200.0.1:2222 -> ClientA

6、ClientA和ClientB通信所需要的对应关系已经在NAT_A和NAT_B都成功建立了,他们可以相互通信了。ClientA只需要向NAT_B发送信息,ClientB只需要向NAT_A发送信息,他们就能够相互收到。

以上给出的例子是在圆锥型网络下进行分析的。我使用以上原理,实现了Tomb Game的Internet联机版本,在局域网的基础上,增加了一个Touch命令用于建立对应关系,同时需要在一台公网IP的服务器上写一个小程序监听一个固定端口,记录所有客户端主机的公网网络地址。

我一开始测试就不成功,原因很不幸的是,我所在的中国移动无线网络的NAT是对称型,也就是说,我向服务器发送数据时,只要改变一下目的端口,NAT也会建立一个新的对应关系使用一个新的端口和服务器通信。

我看过一些资料,对称型NAT是最坏的情况,我很好奇像QQ程序之类的文件传输是如何实现的,于是抓包分析了一下,发现QQ是使用了数据中转服务器。

对于传输文件,经过中转服务器传输数据给对方,不会对传输速度造成很大影响,甚至有时候会有更好的速度。但是这种做法会加大响应时间,不适合网络游戏联机吧。但我今晚看到舍友在玩互联网CS的时候,他们使用教育网可以和一些在网吧上网的人进行联机游戏。据我所知,教育网不是不能直接连接到电信或者移动的网络上面去的吗?难道我理解错了?

我对P2P通俗易懂的理解》上有13条评论

  1. 膜拜小虾

    教育网不能直接连接到电信或者移动… 不能直接连接又不是不能连接… 那台网吧的服务器有公网IP就可以吧…

    回复
      1. 膜拜小虾

        其实不可能学校只有CERNET出口的… 应该是CERNET ChinaNet双出口的…

        不然学生咋访问网页?

        回复
  2. 膜拜小虾

    教育网不能直接连接到电信或者移动… 不能直接连接又不是不能连接… 那台网吧的服务器有公网IP就可以吧… 浩方 vs什么的应该是基于vpn的..

    回复
    1. Xiaoxia 文章作者

      这个是端口转发吧。vpn是所有的应用程序的网络数据包都会被转发,而且vpn的功能不限于这个,通过vpn可以构建一个虚拟的局域网。

      回复
      1. zhangyud

        还有个东西叫netcat,可以把本地的所有端口上的数据重定向到到locahost:8000,然后远程主机上再把数据重放。

        回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>