关于TCP打洞和UDP打洞
为什么网上讲到的P2P打洞基本上都是基于UDP协议的打洞?难道TCP不可能打洞?还是TCP打洞难于实现?假设现在有内网客户端A和内网客户端B,有公网服务端S。如果A和B想要进行UDP通信,则必须穿透双方的NAT路由。假设为NAT-A和NAT-B。
A 发送数据包到公网S,B发送数据包到公网S,则S分别得到了A和B的公网IP,S也和A B 分别建立了会话,由S发到NAT-A的数据包会被NAT-A直接转发给A,由S发到NAT-B的数据包会被NAT-B直接转发给B,除了S发出的数据包之 外的则会被丢弃。所以:现在A B 都能分别和S进行全双工通讯了,但是A B之间还不能直接通讯。
解决办法是:A向B的公网IP发送一个数据包,则NAT-A能接收来自NAT-B的数据包并转发给A了(即B现在能访问A了);再由S命令B向A的公网IP发送一个数据包,则NAT-B能接收来自NAT-A的数据包并转发给B了(即A现在能访问B了)。以上就是“打洞”的原理。但是TCP和UDP在打洞上却有点不同。这是因为伯克利socket(标准socket规范)的API造成的。UDP的socket允许多个socket绑定到同一个本地端口,而TCP的socket则不允许。
这 是这样一个意思:A B要连接到S,肯定首先A B双方都会在本地创建一个socket,去连接S上的socket。创建一个socket必然会绑定一个本地端口(就算应用程序里面没写端口,实际上也是 绑定了的,至少java确实如此),假设为8888,这样A和B才分别建立了到S的通信信道。接下来就需要打洞了,打洞则需要A和B分别发送数据包到对方 的公网IP。但是问题就在这里:因为NAT设备是根据端口号来确定session,如果是UDP的socket,A B可以分别再创建socket,然后将socket绑定到8888,这样打洞就成功了。但是如果TCPsocket,则不能再创建socket并绑定到 8888了,这样打洞就无法成功。
作者: 王春天 出处: http://www.cnblogs.com/spring_wang/ Email: spring_best@yeah.net QQ交流:903639067
作者: 王春天 出处: http://www.cnblogs.com/spring_wang/ Email: spring_best@yeah.net QQ交流:903639067
QQ群:322581894 关于作者: 大连天翼信息科技有限公司 技术总监。 SNF快速开发平台 创始人。应用平台架构师、IT规划咨询专家、业务流程设计专家。 专注于快速开发平台的开发、代码生成器。同时专注于微软平台项目架构、管理和企业解决方案,多年项目开发与管理经验,精通DotNet系列技术Vue、.NetCore、MVC、Webapi、C#、WinForm等,DB(SqlServer、Oracle等)技术,移动端开发。熟悉Java、VB及PB开发语言。在面向对象、面向服务以及数据库领域有一定的造诣。现从事项目实施、开发、架构等工作。并从事用友软件产品U8、U9、PLM 客开工作。 如有问题或建议,请多多赐教! 本文版权归作者和CNBLOGS博客共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,如有问题,可以通过邮箱或QQ 联系我,非常感谢。