TCP实现P2P通信TCP穿越NAT的方法TCP打洞(附源代码).doc

TCP实现P2P通信TCP穿越NAT的方法TCP打洞(附源代码).doc

  1. 1、本文档共13页,可阅读全部内容。
  2. 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
  3. 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  4. 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
TCP实现P2P通信TCP穿越NAT的方法TCP打洞(附源代码)

TCP实现P2P通信、TCP穿越NAT的方法、TCP打洞(附源代码) ◆◆◆ 作者 ◆◆◆ 谢红伟 · chrys · chrys@163.com · ◆◆◆ 日期 ◆◆◆ 2007-07-24 01:34:57 这个标题用了两个顿号三个名称,其实说得是同一个东西,只是网上有不同的说法罢了,另外好像还有人叫TCP打孔(我的朋友小妞听说后问“要打孔啊,要不要我帮你去借个电钻过来啊?”“~!·¥%……·!”)。 闲话少说,我们先看一下技术背景: Internet的迅速发展以及IPv4 地址数量的限制使得网络地址翻译(NAT,Network Address Trans2lation)设备得到广泛应用。NAT设备允许处于同一NAT后的多台主机共享一个公网(本文将处于同一NAT后的网络称为私网,处于NAT前的网络称为公网) IP 地址。一个私网IP 地址通过NAT设备与公网的其他主机通信。公网和私网IP地址域,如下图所示: 一般来说都是由私网内主机(例如上图中“电脑A-01”)主动发起连接,数据包经过NAT地址SO_REUSEADDR 属性(即允许重用),否则侦听会失败。 S的【协助打洞】连接收到A的申请后通过【主连接】通知B,并将A经过NAT-A转换后的公网IP地址和端口等信息告诉B。 B收到S的连接通知后首先与S的【协助打洞】端口连接,随便发送一些数据后立即断开,这样做的目的是让S能知道B经过NAT-B转换后的公网IP和端口号。 B尝试与A的经过NAT-A转换后的公网IP地址和端口进行connect,根据不同的路由器会有不同的结果,有些路由器在这个操作就能建立连接(例如我用的TPLink R402),大多数路由器对于不请自到的SYN请求包直接丢弃而导致connect失败,但NAT-A会纪录此次连接的源地址和端口号,为接下来真正的连接做好了准备,这就是所谓的打洞,即B向A打了一个洞,下次A就能直接连接到B刚才使用的端口号了。 客户端B打洞的同时在相同的端口上启动侦听。B在一切准备就绪以后通过与S的【主连接】回复消息“我已经准备好”,S在收到以后将B经过NAT-B转换后的公网IP和端口号告诉给A。 A收到S回复的B的公网IP和端口号等信息以后,开始连接到B公网IP和端口号,由于在步骤6中B曾经尝试连接过A的公网IP地址和端口,NAT-A纪录了此次连接的信息,所以当A主动连接B时,NAT-B会认为是合法的SYN数据,并允许通过,从而直接的TCP连接建立起来了。 整个实现过程靠文字恐怕很难讲清楚,再加上我的语言表达能力很差(高考语文才考75分,总分150分,惭愧),所以只好用代码来说明问题了。 // 服务器地址和端口号定义 #define SRV_TCP_MAIN_PORT 4000 // 服务器主连接的端口号 #define SRV_TCP_HOLE_PORT 8000 // 服务器响应客户端打洞申请的端口号 这两个端口是固定的,服务器S启动时就开始侦听这两个端口了。 // // 将新客户端登录信息发送给所有已登录的客户端,但不发送给自己 // BOOL SendNewUserLoginNotifyToAll ( LPCTSTR lpszClientIP, UINT nClientPort, DWORD dwID ) { ASSERT ( lpszClientIP nClientPort 0 ); g_CSFor_PtrAry_SockClient.Lock(); for ( int i=0; ig_PtrAry_SockClient.GetSize(); i++ ) { CSockClient *pSockClient = (CSockClient*)g_PtrAry_SockClient.GetAt(i); if ( pSockClient pSockClient-m_bMainConn pSockClient-m_dwID 0 pSockClient-m_dwID != dwID ) { if ( !pSockClient-SendNewUserLoginNotify ( lpszClientIP, nClientPort, dwID ) ) { g_CSFor_PtrAry_SockClient.Unlock(); return FALSE; } } } g_CSFor_PtrAry_SockClient.Unlock (); return TRUE; } 当有新的客户端连接到服务器时,服务器负责将该客户端的信息(IP地址、端口号)发送给其他客户端。 // // 执行者:客户端A // 有新客户端B登录了,我(客户端A)连接服务器端口 SRV_TCP

文档评论(0)

shenlan118 + 关注
实名认证
内容提供者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档