一日一点RakNet(44)--NAT Type detection

来源:互联网 发布:泰国 知乎 编辑:程序博客网 时间:2024/05/16 11:17

NAT类型检测

 

要完成NAT穿透需要提前确定NAT类型

       NAT穿透的成功几率依赖于NAT使用的算法类型。

 

       Full cone NAT:可以从先前使用过的端口上接收到任何数据报。可以从远端的Peer接收到第一个数据报。

       Address-Restricted cone NAT:只要数据报源IP地址是先前我们发送过数据的系统,那么可以从端口上收到数据。如果两个系统同时发送数据报,可以接收到第一个数据报。否则,在我们发送一个数据报以后才会收到第一个数据报。

       Port-Restricted cone NAT:与Address-restricted cone NAT类似,但是我们需要发送到正确的远端IP和正确的远端端口。到不同目的地的相同的源地址和端口使用相同的映射。

       Symmetric NAT:为每一远端目的地选择同的端口。到不同目的地的相同的源地址和端口使用不同的映射。因为端口号不同,第一次的外部穿透尝试就会失败。如果要使得这种模式工作,它要求有端口预测(MAX_PREICTIVE_PORT_RANGE > 1),以及路由按序选择端口。

 

Success Graph

Router Type

Full cone NAT

Address-Restricted cone NAT

Port-Restricted cone NAT

Symmetric NAT

Full cone NAT

YES

YES

YES

YES

Address-Restricted cone NAT

YES

YES

YES

YES

Port-Restricted cone NAT

YES

YES

YES

NO

Symmetric NAT

YES

YES

NO

NO

 

       NatTypeDetection插件允许你检测你自己的NAT的类型,以及NAT穿透是否可以完成。这个要在加入游戏之前确定。

      

NAT类型检测算法

       1.客户端在相同的IP地址打开两个端口。在NatTypeDetectionClient中,RakNetsocket是第一个端口,c2是第二个端口的socket,这两个socketNatTypeDetection::DetectNATType()中创建。

       2.服务器在同一个IP地址上打开两个端口,以及在三个其他的IP地址上打开一个端口。这个在NatTypeDetectionServer::Startup()函数中完成。第一个IP地址上的第一个端口是正常的RakNet端口。第一个IP地址上的第二个端口是s1p2。其他的三个地址绑定到s2p3, s3p4s4p5

       3.客户端连接到服务器通常是在第一个Ip地址上实现。

       4.客户端请求NAT类型检测开始。

       5.服务器尝试向客户端的第二个端口发送数据。这个端口是前面没有打开过的端口,因此如果接收到了,那么客户端就没有位于NAT之后。这个动作可以再NatTypeDetectionServer::Update()方法中实现,通过STATE_TESTING_NONE_1STATE_TESTING_NONE_2来定义。两次尝试的原因是每一次尝试出现两次。每一次尝试的时间是ping * 3 + 50毫秒。S4P5用在这里。

       6.服务器从不同的IP地址向客户端的不同端口发送数据,这个端口RakNet已经连接。如果接收到了数据,那么客户端可以从已经使用的端口上接收到任何源IP地址的数据报。这个情况通常是full-cone NATs2p3用于这个目的。

       7.在已经连接的Ip地址上从第二个端口发送数据,s102。如果接收到了数据,那么客户端的NAT类型是address-restriced cone NAT

       8.客户端向服务器的另外一个IP地址发送数据,从第一个端口(已经连接)。如果IP地址和端口是相同的,那么客户端使用external IP地址和端口来处理来自相同源地址的所有连接。这个是port-restriced NAT类型。

       9.其他的都是symmetric NAT

 

客户端实现:

       1.创建一个插件实例:NatTypeDetectionServer nayTypeDetectionClient

       2.将插件附加到RakPeerIntance实例上:rakPeer->AttachPlugin( &nayTypeDetectionClient);

       3.连接服务器,等待ID_CONNECTION_REQUEST_ACCEPTED消息。使用如下的代码来使用RakNet提供的免费服务器:rakPeer->(“8.17.250.34”, 60481, 0, 0);

       4.使用服务器的SystemAddress调用DetectNATType

       5.等待ID_NAT_TYPE_DETECTION_RESULT消息

       6.第一个字节包含了你的NAT类型。参考NATTypeDetectionCommon.hNATTypeDetectionResult枚举类型。

       7.为这个枚举类型提供了各种功能函数:CanConnect() NATTypeDetectionResultToString(), NATTypeDetectionResultToStringFriendly()

 

服务器实现:

       1.在某地设置一台主机,不要使用NAT/或者位于防火墙之后。(RakNet提供了一个免费的服务器,地址为8.17.250.3460481,但是为了使用方便,你可能想要维护你自己的主机,以便长时间运行)。服务器必须有足够多的外部IP地址,正如在NAT Type Detection Algorithm中所描述的那样。

       2.创建一个插件实例:NatTypeDetectionServer natTypeDetectionServer

       3.将插件附加到RakPeerInterface实例上:rakPeer->AttachPlugin( &natTypeDetectionServer);

       4.获得系统上的IP地址列表:

       char ipList[ MAXIMUM_NUMBER_OF_INTERNAL_IDS ][ 16 ];

unsigned int binaryAddresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS];

SocketLayer::Instance()->GetMyIP( ipList, binaryAddresses );

       5.调用natTypeDetectionServer.Startup( ip2, ip3, ip4);

       ip2, ip3, ip4必须是没有使用的IP地址。如果你调用RakPeer::Startup()方法中将RakNet绑定到ip1,然后使用2nd4thipList中。

例子:

       参考\Samples\NATCompleteClient中的例子。

 

By北洋小郭

转载请注明出处,请勿用于商业用途,谢谢!

原创粉丝点击