注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

UDP打洞  

2016-10-10 16:28:09|  分类: 网络服务编程技术 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

UDP打洞

从会网络编程开始就知道打洞这个技术,但一直因为各种原因没有深入的学习P2P编程,这两天有时间,从网上把相关的资源下来看了看。

仔细看了看书,才明白了这玩意儿是个啥东东。看下面的例子:

有一个内网的客户端A,其需要通过一个有公网IP地址的NAT(A)电脑访问外网,另外同样有一个内网的客户端B,其需要通过一个有公网IP地址的NATB)电脑访问外网。(注意:AB如果在同一网段时会有所不同,可先假设不在同一网段)。公网上有一台普通的服务器S.

首先,A通过NAT(A)连接到S,B通过NAT(B)连接到S.这样AB都可以通过S获得对方的地址(网络连接的五元组、四元组或者说七元组,看UNIX网络高级编程和APUE)。

但是如果现在A直接向B的外网地址NAT(B)发送UDP包,或者反过来BA的外网地址NAT(A)发送数据,这些数据包就会被丢弃(除非它是一个FULL Clone NAT类型的NAT),因为AB都是和S通讯,大家如果学过网络通讯都应该明白,只有上面说过几元组完全相对他们才会通信,而AB之间对不上,所以直接通信的包就被过滤了。

但是如果改一下,如果A在向NAT(B)发送UDP包的时候儿,S告诉B也向NAT(A)发送一个UDP包,这样,一个新的UDP连接就建立了,而且如果不中断的话,他会一直保持连接。

 

打洞过程:

1.A连接S,打一个洞,洞的指向为A- UDP- S

2.B连接S,打一个洞,洞的指向为B-UDP-S

3.S通知A,告诉它:B想连接你

4.AB发起连接,洞的指向为A -UDP -B,这个包B的路由器NAT(B)收到后不会转发给B,而是丢弃,因为它认为这是个非法的包.

5.S通知B连接A,洞的指向为B-UDP-A,此时AB可以进行双向通信,打洞成功

其实打洞的目的就是为了让上面说的几元组对上,AB二者之间能够互相认知。防止出现你单独访问我,我答理你,你访问我我不答理你的情况。

另外大家有没有发现在网络上介绍TCP打洞的比较少,而且主流的打洞基本都是UDP的,主要原因如下:

TCP是有三次握手来完成的连接,而且如果AB发起TCP连接时如果B没有准备好,这事就麻烦了,因为再次连接时,端口可能就不同了。

所以书上的意思是说,你需要在发送包之间先利用UDP(这玩意儿你不需要创建啊,所以还不如用S发送通知呢)发送一组通信包给对方通知它给已方发送SYN包,而已方要在之后做一个小小的延时(多长凭经验和网络延时的情况)再发送SYN包。

网上还说可以使用SO_REUSEADDR,来绑定同一端口达到与UDP类似的方法。

网上的关于TCP对端口处理不同的说明:

http://f543711700.iteye.com/blog/978887

    但是TCPUDP在打洞上却有点不同。这是因为伯克利socket(标准socket规范)的

API造成的。

    UDPsocket允许多个socket绑定到同一个本地端口,而TCPsocket则不允许。

    这是这样一个意思:A B要连接到S,肯定首先A B双方都会在本地创建一个socket

去连接S上的socket。创建一个socket必然会绑定一个本地端口(就算应用程序里面没写

端口,实际上也是绑定了的,至少java确实如此),假设为8888,这样AB才分别建立了到

S的通信信道。接下来就需要打洞了,打洞则需要AB分别发送数据包到对方的公网IP。但是

问题就在这里:因为NAT设备是根据端口号来确定session,如果是UDPsocketA B可以

分别再创建socket,然后将socket绑定到8888,这样打洞就成功了。但是如果是TCP

socket,则不能再创建socket并绑定到8888了,这样打洞就无法成功。

  评论这张
 
阅读(37)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017