打洞理论是这么说的:如果client A 想要向client B发送一个消息,那么不能直接发送,否则会被NAT拦截。必须通知服务器给client B 发送一个通知,通知client B 向client A的方向打洞,那么以后client A就可以直接跟client B联系了。网上找到的一个解释:
1. Client A向Server发一个UDP包,Server收到后,将发送方的IP地址和UDP端口(NAT A向Server发送UDP包的端口,而不是Client A的4000端口)通知Client B。之后Client B就需要开始向这个IP地址和UDP端口发送UDP包了。当然,在下面第2步还未完成之前,Client B向这个IP地址和UDP端口发送的所有UDP包都会被NAT A丢弃。
2. Client A向NAT B的地址和任意端口发一个包, 发送这个包没有其他目的,只是为了让NAT A认为从NAT B发送来的UDP包是安全的而已。我有一个疑问:就是为什么client A直接向client B发送消息会被NAT拦截,但是clinet B向cilent A发送的打洞消息就不会被client A 的NAT拦截呢???下面是我的想法:
难道是这个client B 给client A 的打洞消息也会被client A 的NAT拦截,但是它的目的已经达到了,就是即使被拦截了,也已经打出了一个洞,从此以后,client A 给client B的消息可以直接发送了。
但是我自己仔细想想不太可能,因为client B给client A 发送的打洞消息被拦截,那么就没有到达client A的这台内网主机,也就不可能在client A的NAT中有这个端口映射,没有端口映射,通过NAT后的clinet A直接发送给clinet B的消息就会加上一个client B 所不知道的外网IP+端口号,对于这个client B的NAT 肯定会拦截。难道NAT只认IP,不认端口;如果clinet B给client A 的外网IP发过打洞消息(即使这个消息被拦截),那么以后通过这个client A的外网发给 client A的消息都不会被拦截;但是,我在一个帖子上面看到,NAT是认IP+端口的,那个人换了一个socket ,因为不同socket绑定的不同的服务器端口,所以他用 socket A接收 client 的请求,用socket B去回复client 的时候,client 不能收到消息,也就是说socket B发出的消息不能达到位于NAT后面的client。而如果他用socket A 接收,用socket A回复的话,可以穿过NAT到达client 主机。
这个说明,NAT是认IP,又认端口的。另外,我自己按照1,2所说的写了自己的代码,但是我是server.client A ,client B,三者同时运行在自己的一台机器上面,我的机器是个内网主机,按照上面的说明,我的client A与clinetB 没法通讯。。知道内网主机不能做server,因为client不能连接到server,但是我的是可以连接上的(貌似是通过模拟的吧,我的server IP地址就是用的内网IP 192.168.0.X),还有就是知道 有些NAT不支持 “内网环回”(貌似这个说法),就是2个clinet A与clinet B不能位于同一个NAT下面,我不知道我的client A 与client B不能通讯的原因是什么:
1.是由于我的打洞做法错误
2.由于不支持 “内网环回”
如果是原因2,那么说明我的打洞做法是正确的,但是为什么这么打洞是正确 的,我已经说了我的理解是这样打洞是行不通的,那么请告诉我为什么这样打洞是正确的
自己想了很久,还是不知道怎么回事,请有经验的高手跟前辈们指教。本人一向很大方分数。散发100,如果答案满意,可以再加。
1. Client A向Server发一个UDP包,Server收到后,将发送方的IP地址和UDP端口(NAT A向Server发送UDP包的端口,而不是Client A的4000端口)通知Client B。之后Client B就需要开始向这个IP地址和UDP端口发送UDP包了。当然,在下面第2步还未完成之前,Client B向这个IP地址和UDP端口发送的所有UDP包都会被NAT A丢弃。
2. Client A向NAT B的地址和任意端口发一个包, 发送这个包没有其他目的,只是为了让NAT A认为从NAT B发送来的UDP包是安全的而已。我有一个疑问:就是为什么client A直接向client B发送消息会被NAT拦截,但是clinet B向cilent A发送的打洞消息就不会被client A 的NAT拦截呢???下面是我的想法:
难道是这个client B 给client A 的打洞消息也会被client A 的NAT拦截,但是它的目的已经达到了,就是即使被拦截了,也已经打出了一个洞,从此以后,client A 给client B的消息可以直接发送了。
但是我自己仔细想想不太可能,因为client B给client A 发送的打洞消息被拦截,那么就没有到达client A的这台内网主机,也就不可能在client A的NAT中有这个端口映射,没有端口映射,通过NAT后的clinet A直接发送给clinet B的消息就会加上一个client B 所不知道的外网IP+端口号,对于这个client B的NAT 肯定会拦截。难道NAT只认IP,不认端口;如果clinet B给client A 的外网IP发过打洞消息(即使这个消息被拦截),那么以后通过这个client A的外网发给 client A的消息都不会被拦截;但是,我在一个帖子上面看到,NAT是认IP+端口的,那个人换了一个socket ,因为不同socket绑定的不同的服务器端口,所以他用 socket A接收 client 的请求,用socket B去回复client 的时候,client 不能收到消息,也就是说socket B发出的消息不能达到位于NAT后面的client。而如果他用socket A 接收,用socket A回复的话,可以穿过NAT到达client 主机。
这个说明,NAT是认IP,又认端口的。另外,我自己按照1,2所说的写了自己的代码,但是我是server.client A ,client B,三者同时运行在自己的一台机器上面,我的机器是个内网主机,按照上面的说明,我的client A与clinetB 没法通讯。。知道内网主机不能做server,因为client不能连接到server,但是我的是可以连接上的(貌似是通过模拟的吧,我的server IP地址就是用的内网IP 192.168.0.X),还有就是知道 有些NAT不支持 “内网环回”(貌似这个说法),就是2个clinet A与clinet B不能位于同一个NAT下面,我不知道我的client A 与client B不能通讯的原因是什么:
1.是由于我的打洞做法错误
2.由于不支持 “内网环回”
如果是原因2,那么说明我的打洞做法是正确的,但是为什么这么打洞是正确 的,我已经说了我的理解是这样打洞是行不通的,那么请告诉我为什么这样打洞是正确的
自己想了很久,还是不知道怎么回事,请有经验的高手跟前辈们指教。本人一向很大方分数。散发100,如果答案满意,可以再加。
“打洞”要借助公网Server有两点原因:一是要让NAT给主机分配端口建立关联;二是要获得主机的公网IP和端口号。这样才能与该主机进行通讯。
如果NAT不支持“内网环回”,同一内网的两台主机就不能通过“打洞”方式通讯。
我的针对的NAT就是所谓的Cone NAT
NAT中,规定收到的包的目的地址不在NAT地址列表中的话,就会被抛弃!现在打洞都要借助于一个中间服务器,把相互参数告知对方。
1.怎样将内网主机作为一个公网主机一样做server?
2.如果是在同一个局域网的话,可以直接用内网IP地址通讯,这样就可以绕过“内网环回”问题。现在我的问题是,如果client A与client B在同一个局域网内部,怎样获得他们的内网IP,因为我的server获得的是他们外网IP,只是他们的端口不同而已。
内网机器无法做公网的server吧,除非进行NAT影射。
2、Server根据外网IP可以判断两台Client是否在同一内网,Client可以自己取出内网IP和端口发包告诉Server。
不一定是哪一个包被nat拦截
1. Client A向Server发一个UDP包,Server收到后,将发送方的IP地址和UDP端口(NAT A向 Server发送UDP包的端口,而不是Client A的4000端口)通知Client B。之后Client B就需要开始 向这个IP地址和UDP端口发送UDP包了。当然,在下面第2步还未完成之前,Client B向这个IP地址和 UDP端口发送的所有UDP包都会被NAT A丢弃。
2. Client A向NAT B的地址和任意端口发一个包, 发送这个包没有其他目的,只是为了让NAT A认为从NAT B发送来的UDP包是安全的而已。
------------------------------------------------------------------------------------
我的成功做法如下:
通信的参与者有三方,分别是P2PServer, PeerServer, PeerClient; 我的业务流程是这样的,PeerServer作为视频源而存在,PeerClient向其请求视频数据然后播放,
PeerServer启动或登录时向P2PServer发送数据包,P2PServer收到的addr则是PeerServer经nat后的ip和端口, 事实上这个数据包如果发送成功,则PeerSever的udp洞已经打开了,P2PServer和PeerServer的会话建立成功,只要每隔一段时间(保险一点可以取30秒)向P2PServer服务器发送心跳包,那么这个会话就不会结束!数据包含有改PeerSever的唯一标识ID, P2PServer可以维护一个PeerServer的信息列表(一下简称会话列表),可以用结构体数组来实现。
当然,PeerServer也不能保证24小时在线,可能因为关机,重启,关闭软件或者包发送失败等, P2PServer并不总是能收到心跳包,所以P2PServer也要定时检验会话列表,如果发现某个会话的上次心跳时间距离现在已经超过两分钟,则视为其PeerServer掉线,将该会话信息删除这时候PeerClient只要知道PeerServer经NAT后的IP和Port就能直接和PeerServer进行通信, 怎么知道? 当然是向P2Pserver查询了!
2 x,y两都是私有IP(i.e. 两台机器都位于内网)。
不知道认远程发送端口的NAT占得比例多大。
内网主机使用的端口是不是要端口映射啊???