本人在最近正在做工作相关的UDP网络通信的开发,想把可在局域网上运行的程序搬到公网上去,但是涉及到一个问题,所有客户端跟服务器通讯没有问题,但是客户端与客户端之间的通讯受到了阻碍。这期间也看了不少先辈们的相关资料,到处都是打洞的源代码,但是我始终有点想不通:
NAT有几种形式,能够实现UDP的打洞的只有NPAT亦即CONE NAT,这种NAT共享一个外部地址,通过建立SESSION,分配不同的端口号来帮助内部的客户机通信。
由于存在第三方的SERVER,分别位于两个NAT内的客户机CA和CB想要互相通信,需要先向SERVER发出一个P2P打洞请求。
这里有一点不明白:CA向SERVER注册自己时,其NAT为其打开了一个端口6001,于是,CA与服务器可以互相通信;另个CB向SERVER注册自己时,其NAT为其打开了一个端口8002,CB也可以与SERVER正常通信。当然,这两个操作都是由客户端首先发起的,NAT允许内部与外部主动通信,并且经由原地址(也就是服务器地址)返回的消息,可以正常接收。但是对于CA打开的6001端口和CB打开的8002端口,任何非来自于SERVER的UDP包将被各自的NAT所抛弃。
现在问题出来了:我看到很资料上说,CA如果想与CB直接通信,需要先向SERVER发出一个请求,让服务器发给CB一个命令,命令CB向CA发起一个打洞的数据包,CA做出回应,各自建立数据通道,也就是各自的NAT上的SESSION。但是!服务器可以发给CB一个命令,因为是CB注册服务器时主动联接的服务器,CB也可以遵从命令向CA发出一个打洞请求。这里的打洞请求的地址应该是多少呢?也许有人说,CA不是向服务器注册地址了吗?服务器肯定记录了CA的6001端口。不错,我们可以向6001发出数据包。由于这个数据包不是SERVER发起的,而6001是为了与SERVER通信才建立的,那么,CA的NAT肯定会抛弃这个不请自来的数据包。但是,也有人提到,此时即使CB向CA的请求被拒绝,但是此时也在CB的NAT上建立了一个SESSION,打开了一个指向CA的端口(这是我猜的,比如是8003)。但是CA还不知道,服务器怎么知道?服务器不知道的话,怎么把这个消息告诉给CA?CA的回复打洞请求的数据包发向哪个地址?以后与CB的通信,岂非需要单独保留一个地址?
诚邀各位高手不吝赐教!