关于采用UDP协议进行打洞以进行P2P会话的原理,我本来想写一篇文章作说明,但是现在已经有一篇文章把原理性的东西解释清楚了,我在这里不再作这部分的重复,可以参见这里:
P2P 之 UDP穿透NAT的原理与实现(附源代码)--http://www.cnpaf.net/Class/hack/0512182034513804825.htm
下面解释一下上面的文章中没有提及或者说我觉得比较欠缺的地方.
私有地址/端口和公有地址/端口:我们知道,现在大部分网络采用的都是NAPT(Network Address/Port Translator)了,这个东东的作用是一个对外的对话在经过NAT之后IP地址和端口号都会被改写,在这里把一次会话中客户自己认为在使用的IP地址和端口号成为私有地址/端口,而把经过NAPT之后被改写的IP地址和端口号称为公有地址/端口.或者可以这么理解,私有地址/端口是你家里人对你的昵称而公有地址/端口则是你真正对外公开的名字.如何获得用户的私用地址/端口号,这个很简单了,而要得到公有地址/端口号就要在连接上另一台机器之后由那台机器看到的IP地址和端口号来表示.
如果明白了上面的东西,下面进入我们的代码,在这里解释一下关键部分的实现:
客户端首先得到自己的私有地址/终端,然后向server端发送登陆请求,server端在得到这个请求之后就可以知道这个client端的公有地址/终端,server会为每一个登陆的client保存它们的私有地址/端口和公有地址/端口.
OK,下面开始关键的打洞流程.假设client A要向client B对话,但是A不知道B的地址,即使知道根据NAT的原理这个对话在第一次会被拒绝,因为client B的NAT认为这是一个从没有过的外部发来的请求.这个时候,A如果发现自己没有保存B的地址,或者说发送给B的会话请求失败了,它会要求server端让B向A打一个洞,这个B->A的会话意义在于它使NAT B认为A的地址/端口是可以通过的地址/端口,这样A再向B发送对话的时候就不会再被NAT B拒绝了.打一个比方来说明打洞的过程,A想来B家做客,但是遭到了B的管家NAT B的拒绝,理由是:我从来没有听我家B提过你的名字,这时A找到了A,B都认识的朋友server,要求server给B报一个信,让B去跟管家说A是我的朋友,于是,B跟管家NAT B说,A是我认识的朋友,这样A的访问请求就不会再被管家NAT B所拒绝了.简而言之,UDP打洞就是一个通过server保存下来的地址使得彼此之间能够直接通信的过程,server只管帮助建立连接,在建立间接之后就不再介入了.
好了,原理性的东西解释到这里,附件中有一个完整的P2P演示程序,命令行模式下,包括server端和client端,在运行的时候首先启动server端,然后打开几个client端分别登陆,之后彼此之间就可以相互通信了.程序在本机上测试通过,也就是测试的环境server和client都是一台机器,还没有在不同的机器上测试过,不知道会不会有问题:)
下载地址:
http://www.cppblog.com/Files/converse/P2PDemo.rar
参考资料:
1)P2P 之 UDP穿透NAT的原理与实现(附源代码)-http://www.cnpaf.net/Class/hack/0512182034513804825.htm
2)王艳平<<Windows网络与通信程序设计>>
iwinux 回复于:2006-09-02 21:04:02
好冷...
怎么没有人回复?
yarco3 回复于:2006-09-02 21:20:46
引用:原帖由 iwinux 于 2006-9-2 21:04 发表
好冷...
怎么没有人回复?
因为没看懂...
为什么不是
当A要和B说话的时候,请server老大先叫一声B, 然后B再出来见A?
为什么开始要被拒绝一次...
benjiam 回复于:2006-09-02 22:15:38
一般啦。
穿nat 只是一个应用。 p2p 不止这么简单啦。
flw 回复于:2006-09-02 22:23:58
引用:原帖由 converse 于 2006-9-2 20:41 发表
2)王艳平<<Windows网络与通信程序设计>>
国家主席江泽民,陪同夫人王艳平,一同会见了来华访问的美国XX代表团。
converse 回复于:2006-09-02 22:43:57
>>为什么开始要被拒绝一次...
因为请求被NAT挡住了,我里面没有具体写NAT的概念,可以到我提供的那两份文档中看看.
converse 回复于:2006-09-02 22:44:58
引用:原帖由 benjiam 于 2006-9-2 22:15 发表
一般啦。
穿nat 只是一个应用。 p2p 不止这么简单啦。
嗯,我也是初学,不知道还有哪些?我这份代码只是演示了打洞的过程,打洞之后的应用没有展开,只是一般的对话而已....
hellhell 回复于:2006-09-02 22:50:22
没做过。。。完全不懂,只能顶一下。
converse 回复于:2006-09-02 22:50:40
引用:
NAPT(The IP Network Address/Port Translator) 为何阻碍了P2P软件的应用?
通过NAPT 上网的特点决定了只能由NAPT内的计算机主动向NAPT外部的主机发起连接,外部的主机想直接和NAPT内的计算机直接建立连接是不被允许的。IM(即时通讯)而言,这意味着由于NAPT内的计算机和NAPT外的计算机只能通过服务器中转数据来进行通讯。对于P2P方式的下载程序而言,意味着NAPT内的计算机不能接收到NAPT外部的连接,导致连接数用过少,下载速度很难上去。因此P2P软件必须要解决的一个问题就是要能够在一定的程度上解决NAPT内的计算机不能被外部连接的问题。
yarco3 回复于:2006-09-02 23:46:54
8明白,那么server又如何和B联系的呢?它也在外面啊.
A ----------------NAT -------------B
| |
| |
Server-----------
这样子.
1. A 准备发东西给 B
2. A告诉server它对 B 感兴趣
3. server向B发送信息
4. B连接到A, 于是A变成了server
....
8过好象就是这样的. 奇怪的就是为什么前面会碰一下?
[ 本帖最后由 yarco3 于 2006-9-2 23:54 编辑 ]
converse 回复于:2006-09-02 23:51:13
引用:原帖由 yarco3 于 2006-9-2 23:46 发表
8明白,那么server又如何和B联系的呢?它也在外面啊.
A ----------------NAT -------------B
| |
| |
Server-----------
B登陆server的时候是不是已经与server建立了链接了?这样NAT B就认为server发送过来的请求是可以通过的了...
lan_wjz 回复于:2006-09-02 23:52:55
^_^,P2p穿越NAT不是很简单的事情啊,和具体的NAT类型是相关的。建议有兴趣的兄弟还是先看看NAT的原理。
yarco3 回复于:2006-09-02 23:57:58
引用:原帖由 converse 于 2006-9-2 23:51 发表
B登陆server的时候是不是已经与server建立了链接了?这样NAT B就认为server发送过来的请求是可以通过的了...
1. A 准备发东西给 B
2. A告诉server它对 B 感兴趣
3. server向B发送信息
4. B连接到A, 于是A变成了server
....
8过好象就是这样的. 奇怪的就是为什么前面会碰一下???
有生命期?
先尝试是否能够正常连接?(why? 发送数据的时间超过了nat中存储的什么ttl?)
[ 本帖最后由 yarco3 于 2006-9-3 00:01 编辑 ]
converse 回复于:2006-09-02 23:59:25
A通过server知道B的地址,而且通过server通知B打洞,这样A才能穿过NAT B呀...
yarco3 回复于:2006-09-03 00:09:04
是这里不能理解,
假设client A要向client B对话,但是A不知道B的地址,即使知道根据NAT的原理这个对话在第一次会被拒绝,因为client B的NAT认为这是一个从没有过的外部发来的请求.这个时候,A如果发现自己没有保存B的地址,或者说发送给B的会话请求失败了
假设client A要向client B对话, 假设它要发的话,直接你说的上面步骤啊...
为什么会"在第一次会被拒绝"...是传输数据超时,A/NAT的那个什么忘掉了?
converse 回复于:2006-09-03 00:19:31
引用:原帖由 yarco3 于 2006-9-3 00:09 发表
是这里不能理解,
假设client A要向client B对话,但是A不知道B的地址,即使知道根据NAT的原理这个对话在第一次会被拒绝,因为client B的NAT认为这是一个从没有过的外部发来的请求.这个时候,A如果发现自己没 ...
唉,我觉得你先好好看NAT的原理,打洞的原理,看看我的代码吧...
yarco3 回复于:2006-09-03 00:31:35
引用:原帖由 converse 于 2006-9-3 00:19 发表
唉,我觉得你先好好看NAT的原理,打洞的原理,看看我的代码吧...
偏不看...
至少从表面上看(人性化的角度上讲), 它没有理由额外要去碰一下. 假如是因为类似有个ttl的限制.
同样也没有理由, 在我和你打电话的时候,忽然说通话中断, 我一句话白说了要重新拨号.
那说明不是偶不对,是线路有问题, 是nat应该保证通信的双方能从开始直到终结...................
说明nat这个协议没设计好...
偶有义务维护人类的感受,没有义务理解机器的想法.
lan_wjz 回复于:2006-09-03 00:34:02
我觉得应该听听有经验的人的意见,这个是不能臆断的,很多公司的firewall很BT的,呵呵,根本不能用一些常规的方法,需要做很多补救措施,比如RTP RELAY, STUN, ALG等等。
converse 回复于:2006-09-03 00:48:47
引用:原帖由 yarco3 于 2006-9-3 00:31 发表
偏不看...
至少从表面上看(人性化的角度上讲), 它没有理由额外要去碰一下. 假如是因为类似有个ttl的限制.
同样也没有理由, 在我和你打电话的时候,忽然说通话中断, 我一句话白说了要重新拨号.
那说明不是 ...
无语...你不了解来龙去脉就自己下结论说别人作的不好,请问你作的多还是别人作的多?
[ 本帖最后由 converse 于 2006-9-3 00:51 编辑 ]
yarco3 回复于:2006-09-03 01:46:30
引用:原帖由 converse 于 2006-9-3 00:48 发表
无语...你不了解来龙去脉就自己下结论说别人作的不好,请问你作的多还是别人作的多?
哈哈...我没说其余部分做得不好啊.
我就说那需要碰一下做得不好啊.
难道他做得多有弱点就不能让做得少的人批判了?
偶要会做,nat不就是我的了...真是的. 所以偶在向你了解那个碰了一下的来龙去脉啊?
你看,你窝藏在某个地方, 要联系你只能通过一个叫nat替你做掩护的同伙. 而你通过nat一直在和老大server交换着不人道的信息. 偶做为打入黑社会集团的卧底接到任务, 要找到为非做歹的你.
难道我会傻傻地直接询问那个可疑人物nat吗?我一定会先取得老大的信任, 然后老大通知你, 你便上当受骗通过nat和我接触...除非某个时刻你对我有怀疑, 认为我有不良动机.....
但这怎么可能呢...你怎么不怀疑你老大啊...
难道是因为长时间通信,你怕被警察监听?
...因为nat不懂数据交流是否会向私有域里写入东西, 为了保证tcp/ip不被劫持, 所以在流入的方向上设置了一个ttl, 一旦时间到就会阻止进入...
可还是老问题...server - B A -B 通信有什么区别? 两个都是B在主动联系外面的server和A.
既然能够保证server不会碰一下,那么也能保证A不会被碰一下才对. 毕竟p2p/nat是两个东西.
算了...不问你了. 这方面偶不是很感兴趣. 问到最后一定让我自己去看...
[ 本帖最后由 yarco3 于 2006-9-3 01:48 编辑 ]
benjiam 回复于:2006-09-03 11:50:20
所以在流入的方向上设置了一个ttl, 一旦时间到就会阻止进入...
你的水平 还不到。你还是学 卷一去吧
醉卧水云间 回复于:2006-09-03 21:29:13
ptop的难点好像不是nat穿透。
achun.shx 回复于:2006-09-03 22:09:03
是不是这个意思,除了server,其它的都是client
server永远知道自己是谁,client也知道server是谁,
client要知道自己是谁,就要问server,server知道所有的client是谁,并告诉他,
这样所有的client就能被确定了.
playmud 回复于:2006-09-03 22:28:00
其实p2p和和NAT没什么太大关系,
也不用非要拒绝一次。
lingshiyong 回复于:2006-09-04 08:53:24
上面谈的主要是p2p聊天,那好实现,但文件共享的UDP穿透就比较难!
急不通 回复于:2006-09-04 08:56:49
就是说跟踪服务器与客户的会话,掐断服务器发送给客户端的开洞通知,就会……
kf701 回复于:2006-09-04 09:37:08
我就喜欢水帖.
chestnut king 回复于:2006-09-04 09:44:37
udp穿透已经有点落伍了吧,现在tcp穿透已经实现,不过穿透里还不是太满意
yulc 回复于:2006-09-04 11:27:26
引用:原帖由 chestnut king 于 2006-9-4 09:44 发表
udp穿透已经有点落伍了吧,现在tcp穿透已经实现,不过穿透里还不是太满意
关于 tcp的穿透能提供更详细的资料吗?
udp的穿透确实非常简单,如果要用它来用P2P还需要做很多额外的工作.
JohnBull 回复于:2006-09-04 11:48:39
第一次“碰”的时候如果对方防火墙发回ICMP PORT UNREACHABLE,本端防火墙的状态跟踪取消了这个NAT存根怎办?
再PS:有server也一样,我在电信的时候做过这个实验,必须在LINUX防火墙上忽略这个UNREACHABLE才行。
[ 本帖最后由 JohnBull 于 2006-9-4 12:04 编辑 ]
cellar 回复于:2006-09-04 14:12:15
这个实现是用火墙相关的,就是说必须是同一个内网ip发到不同点的包是从NAT的一个端口出去的,其实现在很多NAT都不是这样的,另外本人觉得两端PEER都在NAT后面实现起来意义不大,一来现在的AD在双NAT的情况下效率太低,二来NAT的情况太复杂,实现千变万化,不可能找到一个万全的方法,用大量的代码和逻辑来求得很小的一部分带宽没有意义,再则双NAT的网络模型因NAT的服务处理能力有限,常会导致速度波动较大,UPD的流控更加难以控制。
PS:那位仁兄能给些TCP穿透的资料吗?我想了好久都想不通,在我看来:无论怎样,你只能伪装你自己,但不能伪装NAT的包,这是最大的难点,我觉得只有双方同时CONNECT才有可能,但是似乎又要做端口猜测,端口猜测的实现基本上没有意义。
1jjk 回复于:2006-09-04 15:30:30
ip1:port---->对公网的机器----->公网的ip2:port
这时返回信息时
公网的ip2就先连“对公网的机器”,然后对公网的机器去放给内网的ip1:port
补充:内网对内网:
ip1:port---->对公网的机器1----->对公网的机器2------>公网的ip2:port
ip1:port<----对公网的机器1<-----对公网的机器2<------公网的ip2:port
例如QQ或者电骡
不知道我说的对不对!
希望有前辈能具体说说
[ 本帖最后由 1jjk 于 2006-9-4 15:33 编辑 ]
SeaKing911 回复于:2006-09-05 08:24:45
顶一下,继续研究
benlan 回复于:2006-09-05 12:45:09
.假设client A要向client B对话,但是A不知道B的地址,即使知道根据NAT的原理这个对话在第一次会被拒绝,因为client B的NAT认为这是一个从没有过的外部发来的请求.这个时候,A如果发现自己没有保存B的地址,或者说发送给B的会话请求失败了,它会要求server端让B向A打一个洞,这个B->A的会话意义在于它使NAT B认为A的地址/端口是可以通过的地址/端口,这样A再向B发送对话的时候就不会再被NAT B拒绝了.
1)有的NAT需要,A-->B才能,B-->A,但有的NAT是可以直接B-->A的过程
2)还有的NAT在 A-->Serv发了以后的 ip + port和 A-->B的ip + port的port会变了,不是同一port,这样子就会出现穿透不了的情况。这时候 B-->A发的数据就回不过来。
gydoesit 回复于:2006-09-07 12:39:45
是呀,楼主的必须要这样才能成立:
B到server的端口和B和A的端口一样,然而,这种假设未必成立。
是不是!
benlan 回复于:2006-09-07 12:54:08
以前处理过的穿透处理是分
1) 直接 B-->A
2) 必须 先 A-->B 然后才能B-->A
3) 变端口的NAT
这3种两两组合成9种情况处理,应该是 3--3组合的时候是穿透不了的,当时处理的时候是3--3组合时是通过服务器转发的。
后来有朋友告诉我,他们解决了3--3组合这种方式,从一个开源游戏的代码里提出来的,后来没做了,也没关心了
ailantian 回复于:2006-09-24 12:10:14
nat有好几种,这个只是其中一种吧。
最常见的就是用stun server那种。其他的好像不怎么简单实现吧
下面是一些相关的关键词
Full Cone NAT
Address Restricted Cone NAT
Port Restricted Cone NAT
解决办法
ALG
MidCom
STUN
TURN
Full Proxy
[ 本帖最后由 ailantian 于 2006-9-24 12:14 编辑 ]
|