C++实现TCP NAT穿越的思想?

fujialin2011 2011-10-17 10:20:53
1、 S启动两个网络侦听,一个叫【主连接】侦听,一个叫【协助打洞】的侦听。
2、 A和B分别与S的【主连接】保持联系。
3、 当A需要和B建立直接的TCP连接时,首先连接S的【协助打洞】端口,并发送协助连接申请。同时在该端口号上启动侦听。注意由于要在相同的网络终端上绑定到不同的套接字上,所以必须为这些套接字设置 SO_REUSEADDR 属性(即允许重用),否则侦听会失败。
4、 S的【协助打洞】连接收到A的申请后通过【主连接】通知B,并将A经过NAT-A转换后的公网IP地址和端口等信息告诉B。
5、 B收到S的连接通知后首先与S的【协助打洞】端口连接,随便发送一些数据后立即断开,这样做的目的是让S能知道B经过NAT-B转换后的公网IP和端口号。
6、 B尝试与A的经过NAT-A转换后的公网IP地址和端口进行connect,根据不同的路由器会有不同的结果,有些路由器在这个操作就能建立连接,大多数路由器对于不请自到的SYN请求包直接丢弃而导致connect失败,但NAT-A会纪录此次连接的源地址和端口号,为接下来真正的连接做好了准备,这就是所谓的打洞,即B向A打了一个洞,下次A就能直接连接到B刚才使用的端口号了。
7、 客户端B打洞的同时在相同的端口上启动侦听。B在一切准备就绪以后通过与S的【主连接】回复消息“我已经准备好”,S在收到以后将B经过NAT-B转换后的公网IP和端口号告诉给A。
8、 A收到S回复的B的公网IP和端口号等信息以后,开始连接到B公网IP和端口号,由于在步骤6中B曾经尝试连接过A的公网IP地址和端口,NAT-A纪录了此次连接的信息,所以当A主动连接B时,NAT-B会认为是合法的SYN数据,并允许通过,从而直接的TCP连接建立起来了。
各位能说说上面这个过程有什么问题吗?谢谢了
...全文
615 37 打赏 收藏 转发到动态 举报
写回复
用AI写文章
37 条回复
切换为时间正序
请发表友善的回复…
发表回复
lsjlfu2010 2012-08-16
  • 打赏
  • 举报
回复
对于打洞问题一般的解决方案是先TCP打洞,不通则UDP打洞,都实现不了那就没办法,只能中转了,具体思想你说得很清楚了
huliang66 2011-11-16
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 danscort2000 的回复:]

看过TCP/IP协议卷吧?
放弃TCP穿透 [UPNP除外,这个不算],这个只是理论上的东西
使用UDP
具体原因无法一次说明白
但你可以参考CISCO 华为等主流设备关于NAT默认模式的说明
网上你能找到的资料,所谓能TCP穿透的,我估计没有一个是经得起实际考验的 [别说用的是TP-LINK路由]

你可以让那些说TCP可以穿透的兄台,提供一套真正投入实际使用的软件名称出来 [不……
[/Quote]

详细的说说呗,让大家学习学习
dfasri 2011-11-14
  • 打赏
  • 举报
回复
[Quote=引用 34 楼 fujialin2011 的回复:]

基本思想是这样的:
每个客户端都有一个连接和服务端是连着的,当要打洞的时候,客户端去连接服务端的辅助打洞端口,并发送目标给服务端,同时在该端口上启动监听,等待连接的到来,服务端响应accept后解析的到客户端映射的IP和端口号,收到目标以后通过主连接把IP和端口号及相应信息发给目标客户,目标客户收到信息后响应该消息,具体就是,连接服务端辅助端口,发送目标信息,同时尝试性的连接得到的IP和端口号……
[/Quote]

明白了. 也就是两个客户端轮流监听接收, 要是这边监听后, 另一边连接不上, 就换个位置, 另一边做监听, 让这边尝试连接过去的意思..那么对于UDP来说, 没监听就是直接乱发数据了, 只要任何一方能够收到一次, 就成功了.
dfasri 2011-11-08
  • 打赏
  • 举报
回复
[Quote=引用 29 楼 fujialin2011 的回复:]
过程不是那么简单的,这里面PORT一致是技术难点,围绕这个问题会出一大堆问题
[/Quote]

过程中, 好像是要求服务器跟A客户端同时向B客户端的IP发送数据. 是不是呢? 不过都是道听途说, 没实际研究过, 也不知道为何...期待可以说说
fujialin2011 2011-11-08
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 dfasri 的回复:]

引用 29 楼 fujialin2011 的回复:
过程不是那么简单的,这里面PORT一致是技术难点,围绕这个问题会出一大堆问题


过程中, 好像是要求服务器跟A客户端同时向B客户端的IP发送数据. 是不是呢? 不过都是道听途说, 没实际研究过, 也不知道为何...期待可以说说
[/Quote]
上面过程已经说得很清楚啦,但是代码实现方式不一样,思想差不多的
cchvsgame 2011-11-08
  • 打赏
  • 举报
回复
还好吧,太长
fujialin2011 2011-11-08
  • 打赏
  • 举报
回复
基本思想是这样的:
每个客户端都有一个连接和服务端是连着的,当要打洞的时候,客户端去连接服务端的辅助打洞端口,并发送目标给服务端,同时在该端口上启动监听,等待连接的到来,服务端响应accept后解析的到客户端映射的IP和端口号,收到目标以后通过主连接把IP和端口号及相应信息发给目标客户,目标客户收到信息后响应该消息,具体就是,连接服务端辅助端口,发送目标信息,同时尝试性的连接得到的IP和端口号,如果连接成功,说明打洞成功了,这儿一般不会成功,环境决定的,没有成功就在这个端口上启动监听并且等待连接的到来,服务端收到这个客户端响应的回复以后以相同的方式发送消息给发起方,发起方收到以后就去连接响应的IP和端口,如果连接成功,打洞就成功了,否则打洞失败!大体就是这样
dfasri 2011-11-08
  • 打赏
  • 举报
回复
我比较笨. 还是不明白...TCP你采用ACK的等待时差来做这个打洞. 但UDP没有ACK可言的, 难道是发送一个很大的数据包来插队?
fujialin2011 2011-11-07
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 dfasri 的回复:]

引用 24 楼 fujialin2011 的回复:

代码实现了,在调试,中间出现了些问题,在处理


成功了就太好了, 虽然我连UDP打洞也不会, 不过看了你写的过程以后, 我想我应该会了...
应该就是单纯的大家都向服务器发送一下数据, 让服务器直接可知道两者的IP和PORT, 然后把两者的IP和PORT都告知双方, 然后双方拿着这对方的外网IP和PORT直接发数据就可以了. 由……
[/Quote]
过程不是那么简单的,这里面PORT一致是技术难点,围绕这个问题会出一大堆问题
dfasri 2011-11-07
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 jiangyiaxiu 的回复:]
UDP没有CONNECT,那怎么建立连接?
[/Quote]

UDP就是不用连接, 所以方便嘛...
督门提码 2011-11-07
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 dfasri 的回复:]

引用 24 楼 fujialin2011 的回复:

代码实现了,在调试,中间出现了些问题,在处理


成功了就太好了, 虽然我连UDP打洞也不会, 不过看了你写的过程以后, 我想我应该会了...
应该就是单纯的大家都向服务器发送一下数据, 让服务器直接可知道两者的IP和PORT, 然后把两者的IP和PORT都告知双方, 然后双方拿着这对方的外网IP和PORT直接发数据就可以了. 由……
[/Quote]
UDP没有CONNECT,那怎么建立连接?
chenjiawei007 2011-11-04
  • 打赏
  • 举报
回复
你第一个连接还连着吗?

第一个连接,连接上后,断开,然后REUSEADDR,重用端口。然后第二个连接用这个地址进行去连接。
fujialin2011 2011-11-04
  • 打赏
  • 举报
回复
就是通过HTTP代理上网的局域网
督门提码 2011-11-04
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 fujialin2011 的回复:]

就是我用同一个SOCKET通过代理连接出去,第一次成功了,但是第二次连接的话报错,错误码是:
WSAEISCONN
10056
A connect request was made on an already connected socket.
[/Quote]

你具体环境是怎么搭建的啊?这个现在我没发生。
dfasri 2011-11-04
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 fujialin2011 的回复:]

代码实现了,在调试,中间出现了些问题,在处理
[/Quote]

成功了就太好了, 虽然我连UDP打洞也不会, 不过看了你写的过程以后, 我想我应该会了...
应该就是单纯的大家都向服务器发送一下数据, 让服务器直接可知道两者的IP和PORT, 然后把两者的IP和PORT都告知双方, 然后双方拿着这对方的外网IP和PORT直接发数据就可以了. 由于TCP有connect过程, 所以比较麻烦, UDP没有connect, 直接发, 直接收. 方便简单.
不知道是不是.

成功了要上来招摇招摇
chenjiawei007 2011-11-04
  • 打赏
  • 举报
回复
汗,真无语了,自己慢慢摸索吧
fujialin2011 2011-11-04
  • 打赏
  • 举报
回复
代码实现了,在调试,中间出现了些问题,在处理
dfasri 2011-11-04
  • 打赏
  • 举报
回复
[Quote=引用楼主 fujialin2011 的回复:]
1、 S启动两个网络侦听,一个叫【主连接】侦听,一个叫【协助打洞】的侦听。
2、 A和B分别与S的【主连接】保持联系。
3、 当A需要和B建立直接的TCP连接时,首先连接S的【协助打洞】端口,并发送协助连接申请。同时在该端口号上启动侦听。注意由于要在相同的网络终端上绑定到不同的套接字上,所以必须为这些套接字设置 SO_REUSEADDR 属性(即允许重用),否则侦听会失败。
4、 S的……
[/Quote]

非常详细的过程描述. 怎样, 楼主实现了没有?
fujialin2011 2011-11-04
  • 打赏
  • 举报
回复
还连着的,再去连报
ERROR_INVALID_PARAMETER
87
0x57
The parameter is incorrect.
这里我用DisconnectEx去断开连接的,然后用ConnectEx连接
fujialin2011 2011-11-03
  • 打赏
  • 举报
回复
这里面涉及到一个问题,就是你的几次连接映射出去的端口号必须一致,要不打洞肯定失败!
加载更多回复(15)

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧