在当前IPv4NAT盛行的网络环境下,两个用户要直接进行P2P连接是非常困难的。较好的解决办法是借助含公网的用户或是服务器中介实现P2P连接。

    NAT:Network Address Translation,网络地址转换。由于IPv4地址数量十分有限,不可能每一台网络设备都能拥有一个IP。于是NAT技术很好地解决了这个问题。路由设备被ISP分给一个公网地址,路由设备自己生成另外的局域网地址,局域网内部的信息通过路由器的网络地址转换,实现内部网络与外部网络的通信。

    对于通常的NAT,当一个内部地址向外部某个网络发送信息:当信息到达NAT设备,NAT设备会首先查询自己的地址转换表。看是否有该内部地址-端口的地址转换表,如果没有,路由器会分配给该地址-端口一个可用的外网端口,并记录在地址转换表中。发送的数据包的源地址会修改为NAT设备的公网地址,端口会变为分配的端口(注意,是直接把IP头部的内容修改了,外部网络是没办法从协议头中知道NAT内部主机的地址的), 然后发送至指定的外部地址。

    外部的数据发往内部的某个地址:刚才提到了,外部网络几乎是不知道目的内网的地址的。他只知道该公网路由器的IP和端口(这种情况都是因为内部实现联络了外网才有外部向该内网通信)。外网只关心之前路由器发给他的数据是哪个地址哪个端口。发送信息就朝着这个地址和端口发送。因为NAT设备上有相应的地址转换表。发往改端口的数据会映射到内网的对应地址和端口。

    

    当内网的设备向外网发送数据,NAT设备会使用公网IP以及自己分配的端口为内网设备转发以及接收数据。生成的转换表有会有一定的时限。大多数路由器接收数据要按照内部的地址信任表来,即:内网设备A通过NAT设备S发送至外网设备B,B可以根据S发送过来的端口发给S然后转到A。但是网络中另一个知道A在NAT上的地址与端口的设备C缺不能通过该端口通过S发送到A。因为A没有给C发送数据,路由器S并不信任C只信任B。但如果此时A再向C发送数据,此时就能使得S添加对C的信任,使得C能够通过S发送数据到A。

    通过上面的这种理论,我们就能实现不同NAT间的网络穿越。我们需要利用一个中介服务器来传递需要连接的设备在NAT设备上的IP与端口信息。


    UDP实现NAT穿越(UDP打洞):

    服务器用来接收需要进行NAT穿越的设备在NAT设备上的IP和端口,假如有两个设备A和B要建立连接,他们先要分别向服务器发送一个UDP数据包。服务器可以通过数据包得到A与B在NAT路由器上转换后的IP和端口。此时A向服务器发送一个向B连接的请求,服务器便把B的地址-端口信息发送给A,通知A向B发送连接,并把A的信息发送个给B并通知他连接A。此时A和B都知道对方的IP与端口信息。各自先向对方地址发送一个UDP数据包。这是会有几种情况:

        1、A和B都收到了对方发送的数据。(这种情况可能是至少有一个路由器已经信任对方的地址或是路由器不进行地址信任。也可能是网络传输速度慢。两个路由器都发送出数据后,数据才到达两个设备,此时两个设备早已相互信任)

        2、A或B只有一个收到了对方发送的数据。(这是最常见的情况,因为两个数据包到达有先后,先发送数据的路由器已经对发送的地址产生了信任,而另一个路由器由于还没有发送数据包就收到了数据,此时它是不信任该地址发过来的数据包的)

        3、都没有收到数据包(

            a、A或B在NAT设备上的端口发生改变 

            b、A与B属于同一NAT下,NAT设备不支持回环转换或做了连接限制

            c、NAT一个端口只信任一个外部地址

        )

如果是第三种情况,可能A与B就不能通过这种环境实现UDP的穿越。对于第二种情况,A与B需要在几秒后再发送几次数据包。如果还是一方全部都收不到。可能收不到这方的NAT设备上的端口发生改变或是NAT一个端口只信任一个外部地址,无法连接。但是通常都能成功的。

    说一下移动通信商网络的NAT。中国联通的NAT是这样的:我使用联通设备向服务器发送UDP数据包,服务器获得的端口号是xxx,而我却不能与另一设备实现NAT穿越。最后经我调试发现,我向另一设备发送数据NAT转换后的端口又是另一个端口。我再向服务器发数据,却是原来的xxx端口。查阅资料发现,联通使用的是NAT3,对于不同的地址,NAT转换为不同的端口进行通信。因此不能普通地通过从服务器收到的端口进行连接。



程序实现:

首先两个需要打洞的设备连接上位于公网118.112.50.95 的服务器(受条件限制,其中有一个设备也处于118.112.50.95的公网NAT下)。并获得对方的IP和端口


wKioL1S3dpzgo4xXAAD0y40h-oY115.jpg

因为此设备也位于服务器所在的公网下,但是是在NAT后的,他自己的公网ip也是118.112.50.95

对方设备的ip是118.113.89.4



wKiom1S3ddCzk4xKAAEDtdCRTq8703.jpg

此设备的ip:118.113.89.4,对方的ip为118.112.50.95




然后我们用第一个设备(118.112.50.95)向服务器发起UDP连接(118.113.89.4)的请求,让服务器告知(118.113.89.4)的设备连接自己。之后双方会每隔几秒向对方送一个hellow数据。共发送五次

wKioL1S3dpyTaDWGAAE7dnrneds936.jpg

该设备收到5次hellow


wKiom1S3ddCx4JM9AAFCqEQGCdY703.jpg

该设备只收到了4次hellow。因为这个设备是被发起连接的设备,所以发送数据包要晚一些。118.112.50.95先发过来的数据包的地址由于不被信任而被丢弃了。当自己向118.112.50.95发出数据包后。服务器开始信任118.112.50.95,于是就收到了118.112.50.95发送过来的剩下的条数据包。


附件所附带的程序是中介服务器与客户端混合在一起的(左边下角,右下角客户端)。左边在公网设置监听端口后就可以用另外的程序连接了。客户端在左上角列表选中要连接的目的地址即通知服务器发起连接。